2014-09-12 26 views
5

Sayısal hesaplamalar için bazı işlevler oluşturmak için semiyeyi kullanıyorum. Bu nedenle, bir ifadeyi numpy dizileriyle kullanmak için bir vektörü lamine edebilirim. İşte bir örnek:Hızlandırılmış semy-lamdified ve vectorized işlevi

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 

sympy sürümü ve saf numpy sürümü arasında sorun hız yani

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 

Yani almak için herhangi bir yol yoktur numpy versiyonunun hızına daha yakın mı? Bence np.vectorize oldukça yavaş ama bir şekilde kodumun bir kısmı onsuz çalışmıyor. Önerileriniz için teşekkürler.

DÜZENLEME: yüzden vectorize işlevi gereklidir nedenini, yani bulundu:

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

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

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

1 gibi basit ifadesi için:

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]) 

bu ancak iyi çalışıyor görünüyor Bu işlev bir dizi döndürmez. Bunu düzeltmenin bir yolu var mı? Bu bir çeşit hata ya da en azından tutarsız tasarım değil mi? Bu durumda np.vectorize() kullanma

cevap

3

lambdify sabitleri için tek bir değer verir. Bu, lambdify çalışma biçiminden kaynaklanmaktadır (bkz. https://stackoverflow.com/a/25514007/161801).

Ancak bu genellikle bir sorun değildir, çünkü sabit, bir diziyle kullandığınız herhangi bir işlemde otomatik olarak doğru şekle yayınlanır. Öte yandan, aynı sabit bir dizi ile açıkça çalıştıysanız, çok daha az verimli olur, çünkü aynı işlemleri birden çok kez hesaplarsınız.

+0

Cevabınız için teşekkür ederiz. Benim problemim, self.T = T (x, y, z) gibi bir şeye sahip olduğum için bu durumda yayın çalışmıyor. Bunu yapmanın en iyi yolu ne olurdu? – jrsm

+0

'numpy.array' bir diziyle çağrıldığında no-op'tur, bu yüzden sonucun her zaman bir dizi olduğundan emin olmak için 'np.array (T (x, y, z))' kullanabilirsiniz. – asmeurer

+0

Yine de kullanım durumunuzun neden yayında çalışmıyor olduğunu anlamıyorum. – asmeurer

3

x, y ve z ilk boyut üzerinde döngü gibi olduğunu ve daha yavaş olur bu yüzden. np.vectorize()IF'a ihtiyacınız yoktur, Numpe'nin işlevlerini kullanmak için lambdify()'a söylersiniz, bu tam olarak yaptığınız şeydir. Daha sonra, kullanılarak:

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 

karşılaştırılabilir bir performans sağlar: bir numpy fonksiyonları söz konusu olduğundan

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

Haklısınız ama bu sabit bir çözüm için işe yaramıyor. – jrsm

+0

@jrsm haklısın ... Hatta denedim bile f = lambdify (x, (cte * np.ones_like (x))) ve lambdify her zaman 'cte' değerini döndürür ... bu muhtemelen bir hatadır Ben onların sorunları listesinde bir sorun açacaktır ... umarım cevabım her neyse ... –

İlgili konular