2014-09-12 16 views
5

Tôi đang sử dụng sympy để tạo ra một số hàm để tính toán số. Vì vậy, tôi lambdify một biểu thức một vectorize nó để sử dụng nó với mảng numpy. Dưới đây là một ví dụ:Tăng tốc chức năng sympy-lamdified và vectorized

import numpy as np 
import sympy as sp 

def numpy_function(): 
    x, y, z = np.mgrid[0:1:40*1j, 0:1:40*1j, 0:1:40*1j] 
    T = (1 - np.cos(2*np.pi*x))*(1 - np.cos(2*np.pi*y))*np.sin(np.pi*z)*0.1 
    return T 

def sympy_function(): 
    x, y, z = sp.Symbol("x"), sp.Symbol("y"), sp.Symbol("z") 
    T = (1 - sp.cos(2*sp.pi*x))*(1 - sp.cos(2*sp.pi*y))*sp.sin(sp.pi*z)*0.1 
    lambda_function = np.vectorize(sp.lambdify((x, y, z), T, "numpy")) 
    x, y, z = np.mgrid[0:1:40*1j, 0:1:40*1j, 0:1:40*1j] 
    T = lambda_function(x,y,z) 
    return T 

Vấn đề giữa phiên bản sympy và một phiên bản numpy tinh khiết là tức tốc

In [3]: timeit test.numpy_function() 
100 loops, best of 3: 11.9 ms per loop 

vs

In [4]: timeit test.sympy_function() 
1 loops, best of 3: 634 ms per loop 

Vậy có cách nào để có được gần với tốc độ của phiên bản numpy? Tôi nghĩ rằng np.vectorize là khá chậm nhưng bằng cách nào đó một số phần của mã của tôi không hoạt động mà không có nó. Cảm ơn bạn đã đề xuất.

EDIT: Vì vậy, tôi tìm thấy lý do tại sao chức năng vectorize là cần thiết, ví dụ:

In [35]: y = np.arange(10) 

In [36]: f = sp.lambdify(x,sin(x),"numpy") 

In [37]: f(y) 
Out[37]: 
array([ 0.  , 0.84147098, 0.90929743, 0.14112001, -0.7568025 , 
     -0.95892427, -0.2794155 , 0.6569866 , 0.98935825, 0.41211849]) 

này dường như làm việc tốt tuy nhiên:

In [38]: y = np.arange(10) 

In [39]: f = sp.lambdify(x,1,"numpy") 

In [40]: f(y) 
Out[40]: 1 

Vì vậy, đối biểu hiện đơn giản như 1 hàm này không trả về một mảng. Có cách nào để sửa lỗi này và đây không phải là loại lỗi hoặc thiết kế ít nhất không nhất quán?

Trả lời

3

lambdify trả về một giá trị duy nhất cho các hằng số vì không có chức năng NumPy có liên quan. Điều này là do cách thức hoạt động của lambdify (xem https://stackoverflow.com/a/25514007/161801).

Nhưng điều này thường không phải là một vấn đề vì một hằng số sẽ tự động phát sóng đến hình dạng chính xác trong bất kỳ thao tác nào mà bạn sử dụng nó với một mảng. Mặt khác, nếu bạn làm việc một cách rõ ràng với một mảng có cùng một hằng số, nó sẽ kém hiệu quả hơn nhiều vì bạn sẽ tính toán các phép toán giống nhau nhiều lần.

+0

Cảm ơn bạn đã trả lời. Vấn đề của tôi là tôi có một cái gì đó như self.T = T (x, y, z) vì vậy trong trường hợp này phát sóng không hoạt động. Cách nào tốt nhất để làm việc này ? – jrsm

+0

Có vẻ như 'numpy.array' là một no-op khi được gọi với một mảng, vì vậy bạn có thể sử dụng' np.array (T (x, y, z)) 'để đảm bảo rằng kết quả luôn luôn là một mảng. – asmeurer

+0

Mặc dù tôi vẫn không hiểu tại sao trường hợp sử dụng của bạn không hoạt động với phát sóng. – asmeurer

3

Sử dụng np.vectorize() trong trường hợp này cũng giống như vòng lặp qua chiều kích đầu tiên của x, yz, và đó là lý do tại sao nó trở nên chậm hơn. Bạn không cần np.vectorize()NẾU bạn yêu cầu lambdify() để sử dụng các chức năng của NumPy, đó chính xác là những gì bạn đang làm. Sau đó, sử dụng:

def sympy_function(): 
    x, y, z = sp.Symbol("x"), sp.Symbol("y"), sp.Symbol("z") 
    T = (1 - sp.cos(2*sp.pi*x))*(1 - sp.cos(2*sp.pi*y))*sp.sin(sp.pi*z)*0.1 
    lambda_function = sp.lambdify((x, y, z), T, "numpy") 
    x, y, z = np.mgrid[0:1:40*1j, 0:1:40*1j, 0:1:40*1j] 
    T = lambda_function(x,y,z) 
    return T 

làm cho việc thực hiện so sánh:

In [26]: np.allclose(numpy_function(), sympy_function()) 
Out[26]: True 

In [27]: timeit numpy_function() 
100 loops, best of 3: 4.08 ms per loop 

In [28]: timeit sympy_function() 
100 loops, best of 3: 5.52 ms per loop 
+0

Bạn nói đúng nhưng điều này không có tác dụng đối với giải pháp không đổi. – jrsm

+0

@ jrsm bạn nói đúng ... Tôi đã thử ngay cả 'f = lambdify (x, (cte * np.ones_like (x)))' và 'lambdify' trả về luôn giá trị' cte' ... đây có thể là lỗi , Tôi sẽ mở một vấn đề trong danh sách các vấn đề của họ ... hy vọng câu trả lời của tôi đã giúp bạn ... –

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