7

Gần đây tôi đã trả lời để THIS câu hỏi mà muốn nhân của 2 danh sách, một số người dùng gợi ý theo cách sau sử dụng NumPy, bên cạnh tôi mà tôi nghĩ là cách thích hợp:Tại sao việc đọc danh sách nhanh hơn nhiều so với việc gộp mảng để nhân mảng?

(a.T*b).T 

Ngoài ra tôi thấy rằng aray.resize() có cùng hiệu suất như thế. cách nào câu trả lời khác đề nghị một giải pháp sử dụng danh sách hiểu:

[[m*n for n in second] for m, second in zip(b,a)] 

Nhưng sau khi benchmark tôi thấy rằng danh sách hiểu biết thực hiện rất nhanh hơn NumPy:

from timeit import timeit 

s1=""" 
a=[[2,3,5],[3,6,2],[1,3,2]] 
b=[4,2,1] 

[[m*n for n in second] for m, second in zip(b,a)] 
""" 
s2=""" 
a=np.array([[2,3,5],[3,6,2],[1,3,2]]) 
b=np.array([4,2,1]) 

(a.T*b).T 
""" 

print ' first: ' ,timeit(stmt=s1, number=1000000) 
print 'second : ',timeit(stmt=s2, number=1000000,setup="import numpy as np") 

kết quả:

first: 1.49778485298 
second : 7.43547797203 

Như bạn có thể thấy numpy là khoảng 5 lần nhanh hơn. nhưng điều đáng ngạc nhiên nhất là nó nhanh hơn mà không cần dùng transpose, và cho đoạn mã sau:

a=np.array([[2,3,5],[3,6,2],[1,3,2]]) 
b=np.array([[4],[2],[1]]) 

a*b 

Danh sách hiểu vẫn là 5 lần faster.So ngoài của điểm này liệt kê comprehensions thực hiện trong C ở đây chúng tôi sử dụng 2 vòng lặp lồng nhau và một hàm zip Vậy điều gì có thể là lý do? Có phải vì hoạt động * trong không?

Cũng lưu ý rằng không có vấn đề gì với timeit tại đây tôi đã putted import một phần trong setup.

Tôi cũng đã thử nó với arras lớn, sự khác biệt được thấp hơn nhưng vẫn không có ý nghĩa:

s1=""" 
a=[[2,3,5],[3,6,2],[1,3,2]]*10000 
b=[4,2,1]*10000 

[[m*n for n in second] for m, second in zip(b,a)] 
""" 
s2=""" 
a=np.array([[2,3,5],[3,6,2],[1,3,2]]*10000) 
b=np.array([4,2,1]*10000) 

(a.T*b).T 

""" 



print ' first: ' ,timeit(stmt=s1, number=1000) 
print 'second : ',timeit(stmt=s2, number=1000,setup="import numpy as np") 

kết quả:

first: 10.7480301857 
second : 13.1278889179 
+2

.... Thử nhiều mảng lớn hơn? – NightShadeQueen

+0

@NightShadeQueen Tôi đã thử rằng kết quả vẫn giống nhau – Kasramvd

+0

@Kasramvd bạn đã thử bao nhiêu lần? – Falmarri

Trả lời

12

Tạo mảng NumPy là chậm hơn nhiều so với việc tạo ra danh sách:

In [153]: %timeit a = [[2,3,5],[3,6,2],[1,3,2]] 
1000000 loops, best of 3: 308 ns per loop 

In [154]: %timeit a = np.array([[2,3,5],[3,6,2],[1,3,2]]) 
100000 loops, best of 3: 2.27 µs per loop 

Cũng có thể sửa các chi phí phát sinh bởi các cuộc gọi hàm NumPy e thịt của phép tính có thể được thực hiện bởi hàm C/Fortran cơ bản nhanh. Điều này có thể bao gồm việc đảm bảo đầu vào là các mảng NumPy,

Chi phí thiết lập/cố định này cần lưu ý trước khi giả sử các giải pháp NumPy nhanh hơn các giải pháp thuần-Python. NumPy chiếu sáng khi bạn thiết lập các mảng lớn sau khi và sau đó thực hiện nhiều hoạt động NumPy trên các mảng. Nó có thể không hoạt động tốt hơn Python tinh khiết nếu các mảng nhỏ vì chi phí thiết lập có thể lớn hơn lợi ích của việc giảm tải các tính toán thành các hàm C/Fortran đã biên dịch. Đối với các mảng nhỏ, đơn giản có thể không đủ tính toán để làm cho nó đáng giá.


Nếu bạn tăng kích thước của mảng một chút, và di chuyển tạo ra các mảng vào việc thiết lập, sau đó NumPy có thể nhanh hơn nhiều so với Python tinh khiết:

import numpy as np 
from timeit import timeit 

N, M = 300, 300 

a = np.random.randint(100, size=(N,M)) 
b = np.random.randint(100, size=(N,)) 

a2 = a.tolist() 
b2 = b.tolist() 

s1=""" 
[[m*n for n in second] for m, second in zip(b2,a2)] 
""" 

s2 = """ 
(a.T*b).T 
""" 

s3 = """ 
a*b[:,None] 
""" 

assert np.allclose([[m*n for n in second] for m, second in zip(b2,a2)], (a.T*b).T) 
assert np.allclose([[m*n for n in second] for m, second in zip(b2,a2)], a*b[:,None]) 

print 's1: {:.4f}'.format(
    timeit(stmt=s1, number=10**3, setup='from __main__ import a2,b2')) 
print 's2: {:.4f}'.format(
    timeit(stmt=s2, number=10**3, setup='from __main__ import a,b')) 
print 's3: {:.4f}'.format(
    timeit(stmt=s3, number=10**3, setup='from __main__ import a,b')) 

sản lượng

s1: 4.6990 
s2: 0.1224 
s3: 0.1234 
+0

Vì vậy, vấn đề là thử nghiệm ở đây bao gồm việc tạo ra các cấu trúc dữ liệu, và, với việc loại bỏ cấu trúc đó, 'numpy' thực sự sẽ nhanh hơn? – TigerhawkT3

+0

Vâng tôi nghĩ rằng đây là lý do vì khi tôi sử dụng mảng numpy trong danh sách hiểu nó được chậm hơn mà cách tiếp cận numpy! – Kasramvd

+0

Bạn đang sử dụng trình bao/trình thông dịch nào để có thể thực hiện '% timeit python_expression'? –

Các vấn đề liên quan