codememo

목록의 제품 반환

tipmemo 2023. 7. 2. 20:46
반응형

목록의 제품 반환

다음을 수행할 수 있는 더 간결하고 효율적이거나 단순한 비단결적인 방법이 있습니까?

def product(lst):
    p = 1
    for i in lst:
        p *= i
    return p

▁using▁is다▁after▁margin▁than니▁fasterally습▁i되었▁this▁tests몇▁out알▁that게▁some▁have것▁found을는빠지가르다약을 사용하는 것보다 약간 빠르다는 것을 알게 되었습니다.operator.mul:

from operator import mul
# from functools import reduce # python3 compatibility

def with_lambda(lst):
    reduce(lambda x, y: x * y, lst)

def without_lambda(lst):
    reduce(mul, lst)

def forloop(lst):
    r = 1
    for x in lst:
        r *= x
    return r

import timeit

a = range(50)
b = range(1,50)#no zero
t = timeit.Timer("with_lambda(a)", "from __main__ import with_lambda,a")
print("with lambda:", t.timeit())
t = timeit.Timer("without_lambda(a)", "from __main__ import without_lambda,a")
print("without lambda:", t.timeit())
t = timeit.Timer("forloop(a)", "from __main__ import forloop,a")
print("for loop:", t.timeit())

t = timeit.Timer("with_lambda(b)", "from __main__ import with_lambda,b")
print("with lambda (no 0):", t.timeit())
t = timeit.Timer("without_lambda(b)", "from __main__ import without_lambda,b")
print("without lambda (no 0):", t.timeit())
t = timeit.Timer("forloop(b)", "from __main__ import forloop,b")
print("for loop (no 0):", t.timeit())

나에게 주는

('with lambda:', 17.755449056625366)
('without lambda:', 8.2084708213806152)
('for loop:', 7.4836349487304688)
('with lambda (no 0):', 22.570688009262085)
('without lambda (no 0):', 12.472226858139038)
('for loop (no 0):', 11.04065990447998)

람다를 사용하지 않는 경우:

from operator import mul
# from functools import reduce # python3 compatibility
reduce(mul, list, 1)

그것은 더 낫고 더 빠릅니다.python 2.7.5 사용

from operator import mul
import numpy as np
import numexpr as ne
# from functools import reduce # python3 compatibility

a = range(1, 101)
%timeit reduce(lambda x, y: x * y, a)   # (1)
%timeit reduce(mul, a)                  # (2)
%timeit np.prod(a)                      # (3)
%timeit ne.evaluate("prod(a)")          # (4)

다음 구성에서:

a = range(1, 101)  # A
a = np.array(a)    # B
a = np.arange(1, 1e4, dtype=int) #C
a = np.arange(1, 1e5, dtype=float) #D

python 2.7.5를 사용한 결과


|     1     |     2     |     3     |     4     |-------+-----------+-----------+-----------+-----------+A 20.8 µs 13.3 µs 22.6 µs 39.6 µsB 106 µs 95.3 µs 5.92 µs 26.1 µsC 4.34 ms 3.51 ms 16.7 µs 38.9 µsD 46.6 ms 38.5 ms 180 µs 216 µs

결과:np.prod를 사용하면 가장 빠른 것입니다.np.array데이터 구조(소규모 어레이의 경우 18배, 대규모 어레이의 경우 250배)

python 3.3.2와 함께:


|     1     |     2     |     3     |     4     |-------+-----------+-----------+-----------+-----------+A 23.6 µs 12.3 µs 68.6 µs 84.9 µsB 133 µs 107 µs 7.42 µs 27.5 µsC 4.79 ms 3.74 ms 18.6 µs 40.9 µsD 48.4 ms 36.8 ms 187 µs 214 µs

파이썬 3이 더 느립니까?

하는 중Python 3.8함수가 에 포함되었습니다.math표준 라이브러리의 모듈:

math.math(반복 가능, *, 시작=1)

은 것은의결반다환니합를과의 곱을 합니다.start값(기본값: 1) 곱하기 숫자:

import math

math.prod([2, 3, 4]) # 24

로, 한 부분이, 이 에는 "" "" "" "" "" "" ""가됩니다.1 (또는또▁()start값(제공된 경우).

from functools import reduce

a = [1, 2, 3]
reduce(lambda x, y: x * y, a, 1)

목록에 숫자만 있는 경우:

from numpy import prod
prod(list)

EDIT: @off995555가 지적한 것처럼 이는 큰 정수 결과에서는 작동하지 않습니다. 이 경우 유형의 결과를 반환합니다.numpy.int64이안 클렐런드의 해결책은 다음과 같습니다operator.mul그리고.reduce는 반되므로정큰결대작해동다니합을 하므로 큰 할 수 .long.

아무 것도 가져오지 않고 한 줄로 만들고 싶다면 다음과 같이 할 수 있는 것은 다음과 같습니다.

eval('*'.join(str(item) for item in list))

하지만 하지 마세요.

저는 comp.lang.python(죄송하지만 포인터를 만들기에는 너무 게을러서)에 대한 긴 토론을 기억합니다. 그 결과 당신의 원래 정의가 가장 파이썬적이라고 결론을 내렸습니다.

제은당축쓰것는아때이다루작번함한니수것다성니입필호따호요는니입다적썬파이출! 함수는 입니다 - 과 함께 하며, 인 도입 로. 생성자 표현식과 잘 작동합니다. 그리고 성공적으로 도입된 이후로sum()Python은 점점 더 많은 축소 기능이 내장되어 성장하고 있습니다.any()그리고.all()최근에 추가된 것들은...

은 공식적인 것 - 이결은일공것인입다니식적종의론.reduce()다음과 같이 Python 3.0의 기본 제공 프로그램에서 제거되었습니다.

하기"functools.reduce()하지만 99%의 경우 루프에 대한 명시적인 설명이 더 읽기 쉽습니다."

Guido의 지원 인용문(및 해당 블로그를 읽은 Lispers의 일부 지원 의견)은 Python 3000의 축소 운명()을 참조하십시오.

추신: 혹시 필요하시다면product()조합론은 (새로운 2.6)을 참조하십시오.

perfplot(나의 작은 프로젝트)로 다양한 솔루션을 테스트해 본 결과

numpy.prod(lst)

가장 빠른 솔루션입니다(목록이 매우 짧지 않은 경우).

enter image description here


그림을 재현하는 코드:

import perfplot
import numpy

import math
from operator import mul
from functools import reduce

from itertools import accumulate


def reduce_lambda(lst):
    return reduce(lambda x, y: x * y, lst)


def reduce_mul(lst):
    return reduce(mul, lst)


def forloop(lst):
    r = 1
    for x in lst:
        r *= x
    return r


def numpy_prod(lst):
    return numpy.prod(lst)


def math_prod(lst):
    return math.prod(lst)


def itertools_accumulate(lst):
    for value in accumulate(lst, mul):
        pass
    return value


b = perfplot.bench(
    setup=numpy.random.rand,
    kernels=[
        reduce_lambda,
        reduce_mul,
        forloop,
        numpy_prod,
        itertools_accumulate,
        math_prod,
    ],
    n_range=[2 ** k for k in range(20)],
    xlabel="len(a)",
)
b.save("out.png")
b.show()
import operator
reduce(operator.mul, list, 1)

이 답변의 목적은 특정 상황에서 유용한 계산을 제공하는 것입니다. 즉, a) 최종 산출물이 극도로 크거나 극히 작을 수 있도록 많은 수의 값이 곱해지는 경우와 b) 정확한 답변에 대해 별로 신경 쓰지 않고 대신 많은 수의 시퀀스를 갖는 경우입니다.각 제품을 기준으로 주문할 수 있기를 원합니다.

목록의 요소(l은 목록)를 곱하려는 경우 다음을 수행할 수 있습니다.

import math
math.exp(sum(map(math.log, l)))

그 접근법은 다른 사람들처럼 읽기 쉬운 것이 아닙니다.

from operator import mul
reduce(mul, list)

만약 여러분이 reduc()에 익숙하지 않은 수학자라면 그 반대일 수도 있지만, 저는 일반적인 상황에서 그것을 사용하는 것을 추천하지 않을 것입니다.또한 질문에 언급된 제품() 기능보다 읽기가 어렵습니다(적어도 수학자가 아닌 사람에게는).

단, 다음과 같이 언더플로 또는 오버플로의 위험이 있는 경우

>>> reduce(mul, [10.]*309)
inf

그리고 당신의 목적은 제품이 무엇인지 알기보다는 다른 시퀀스의 제품을 비교하는 것입니다.

>>> sum(map(math.log, [10.]*309))
711.49879373515785

이 접근 방식으로 오버플로하거나 언더플로하는 실제 문제가 발생하는 것은 사실상 불가능하기 때문입니다. (그 계산 결과가 클수록 계산할 수 있다면 곱이 더 커질 것입니다.)

아무도 사용을 제안하지 않은 것이 놀랍습니다.itertools.accumulate와 함께operator.mul이렇게 하면 사용할 수 없습니다.reduce3에 것 (Python 2에 3때 ▁(▁to▁the)▁which▁is른▁3에▁pythondue문에▁(다▁for와▁different▁and▁2functools가져오기는 Python 3)에 필요하며, Guido van Rossum 자신은 다음과 같이 비파이썬으로 간주합니다.

from itertools import accumulate
from operator import mul

def prod(lst):
    for value in accumulate(lst, mul):
        pass
    return value

예:

prod([1,5,4,3,5,6])
# 1800

한 가지 옵션은 및 또는 장식가를 사용하는 것입니다.나는 또한 당신의 코드를 한두 번 약간 수정했습니다(적어도 Python 3에서 "list"는 변수 이름에 사용되어서는 안 되는 키워드입니다).

@njit
def njit_product(lst):
    p = lst[0]  # first element
    for i in lst[1:]:  # loop over remaining elements
        p *= i
    return p

타이밍을 위해 먼저 numba를 사용하여 함수를 컴파일하려면 한 번 실행해야 합니다.일반적으로 함수는 처음 호출될 때 컴파일되고 그 후 메모리에서 호출됩니다(더 빠름).

njit_product([1, 2])  # execute once to compile

이제 코드를 실행하면 컴파일된 버전의 함수로 실행됩니다.나는 주피터 노트북과 그들의 시간을 쟀습니다.%timeit마법 기능:

product(b)  # yours
# 32.7 µs ± 510 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

njit_product(b)
# 92.9 µs ± 392 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

파이썬 3.5를 실행하는 내 컴퓨터에서는 네이티브 파이썬for루프가 사실 가장 빨랐습니다.주피터 노트북과 컴퓨터로 누바 장식된 성능을 측정하는 데에는 속임수가 있을 수 있습니다.%timeit마법의 기능위의 타이밍이 정확한지 확신할 수 없으므로 시스템에서 테스트해 보고 numba가 성능을 향상시키는지 확인하는 것이 좋습니다.

가장 빠른 방법은 다음과 같습니다.

mysetup = '''
import numpy as np
from find_intervals import return_intersections 
'''

# code snippet whose execution time is to be measured
mycode = '''

x = [4,5,6,7,8,9,10]
prod = 1
i = 0
while True:
    prod = prod * x[i]
    i = i + 1
    if i == len(x):
        break
'''

# timeit statement for while:
print("using while : ",
timeit.timeit(setup=mysetup,
              stmt=mycode))

# timeit statement for mul:
print("using mul : ",
    timeit.timeit('from functools import reduce;
    from operator import mul;
    c = reduce(mul, [4,5,6,7,8,9,10])'))

# timeit statement for mul:
print("using lambda : ",      
    timeit.timeit('from functools import reduce;
    from operator import mul;
    c = reduce(lambda x, y: x * y, [4,5,6,7,8,9,10])'))

시간은 다음과 같습니다.

>>> using while : 0.8887967770060641

>>> using mul : 2.0838719510065857

>>> using lambda : 2.4227715369997895

OP 테스트에 대한 Python 3 결과: (각각 3개 중 최고)

with lambda: 18.978000981995137
without lambda: 8.110567473006085
for loop: 10.795806062000338
with lambda (no 0): 26.612515013999655
without lambda (no 0): 14.704098362999503
for loop (no 0): 14.93075215499266

가장 빠른 방법은 모르겠지만 라이브러리나 모듈을 가져오지 않고 컬렉션의 제품을 얻을 수 있는 짧은 코드가 있습니다.

eval('*'.join(map(str,l)))

코드는 다음과 같습니다.

product = 1 # Set product to 1 because when you multiply it you don't want you answer to always be 0
my_list = list(input("Type in a list: ").split(", ")) # When input, the data is a string, so you need to convert it into a list and split it to make it a list.
for i in range(0, len(my_list)):
  product *= int(my_list[i])
print("The product of all elements in your list is: ", product)

이것은 부정행위에도 효과가 있습니다.

def factorial(n):
    x=[]
    if n <= 1:
        return 1
    else:
        for i in range(1,n+1): 
            p*=i
            x.append(p)
        print x[n-1]    

언급URL : https://stackoverflow.com/questions/2104782/returning-the-product-of-a-list

반응형