2015-01-25 9 views
5

bir hareket yörüngesinin kesimleri arasında bir enine ürün yerine) (einsum numpy edebilir:Aşağıdaki komut dosyası kullanarak bir hareket yörüngesinin bitişik parçalar (xy koordinatları) enine ürün yerine

In [129]: 
def func1(xy, s): 
    size = xy.shape[0]-2*s 
    out = np.zeros(size) 
    for i in range(size): 
     p1, p2 = xy[i], xy[i+s]  #segment 1 
     p3, p4 = xy[i+s], xy[i+2*s] #segment 2 
     out[i] = np.cross(p1-p2, p4-p3) 
    return out 

def func2(xy, s): 
    size = xy.shape[0]-2*s 
    p1 = xy[0:size] 
    p2 = xy[s:size+s] 
    p3 = p2 
    p4 = xy[2*s:size+2*s] 

    tmp1 = p1-p2 
    tmp2 = p4-p3 
    return tmp1[:, 0] * tmp2[:, 1] - tmp2[:, 0] * tmp1[:, 1] 


In [136]: 
xy = np.array([[1,2],[2,3],[3,4],[5,6],[7,8],[2,4],[5,2],[9,9],[1,1]]) 
func2(xy, 2) 

Out[136]: 
array([ 0, -3, 16, 1, 22]) 

func1 için özellikle yavaş içsel döngüden dolayı, çarpımın kendisinin (func2) büyüklüğünü daha hızlı bir şekilde yeniden yazdım.

Aynı hesaplamayı yapmak için numpy einsum işlevini kullanmak mümkün mü?

+0

Testlerimde 'func2''niz alternatiflerden daha hızlı, hatta yeni 'cross'. – hpaulj

cevap

1

einsum sadece ürün toplamlarını hesaplar, ancak tmp2 sütunları ters ve birinci sütunun işaretini değiştirerek ürünlerin bir miktar içine çapraz ürünü ayakkabı çekeceği olabilir:

def func3(xy, s): 
    size = xy.shape[0]-2*s 
    tmp1 = xy[0:size] - xy[s:size+s] 
    tmp2 = xy[2*s:size+2*s] - xy[s:size+s] 
    tmp2 = tmp2[:, ::-1] 
    tmp2[:, 0] *= -1 
    return np.einsum('ij,ij->i', tmp1, tmp2) 

Ama func3, func2'dan daha yavaştır.

In [80]: xy = np.tile(xy, (1000, 1)) 

In [104]: %timeit func1(xy, 2) 
10 loops, best of 3: 67.5 ms per loop 

In [105]: %timeit func2(xy, 2) 
10000 loops, best of 3: 73.2 µs per loop 

In [106]: %timeit func3(xy, 2) 
10000 loops, best of 3: 108 µs per loop 

Tutarlılık kontrolü:

In [86]: np.allclose(func1(xy, 2), func3(xy, 2)) 
Out[86]: True 

ben func2 burada einsum yenerek nedeni sadece 2 tekrarlamalar için einsum döngü ayarı maliyeti sadece elle yazmaya kıyasla çok pahalı olduğu için olduğunu düşünüyorum toplamı, tersine çevirmek ve çoğaltmak da biraz zaman alır.

+0

Teşekkürler unutbu. Ortak görünüm tabanlı yöntemi kullanarak bir matrisin sütunlarını tersine çevirmenin de oldukça yavaş olduğunu biliyorum. – user3329302

1

np.cross, herhangi bir sorun olmadan yayını gerçekleştirebilen akıllı küçük bir yaratıktır. Yani yeniden yazabilirsiniz senin func2 olarak:

def func2(xy, s): 
    size = xy.shape[0]-2*s 
    p1 = xy[0:size] 
    p2 = xy[s:size+s] 
    p3 = p2 
    p4 = xy[2*s:size+2*s] 
    return np.cross(p1-p2, p4-p3) 

ve doğru sonucu üretecektir: en son Numpy olarak

>>> func2(xy, 2) 
array([ 0, -3, 16, 1, 22]) 

o kadar yeniden yazıldı olarak büyük olasılıkla Kodunuzla daha hızlı bir tad çalışacaktır ara dizi oluşturmayı en aza indirir. Kaynak koduna (saf Python) here bakabilirsiniz.

+0

Referans verdiğiniz "çapraz" sürümün Şubat ve Haziran 2014’te büyük değişiklikler var, v1.9.1. İlgilenilen ekseni sonuna kadar çevirerek ve 'mümkün olduğunca çoğul (..., out = c) 'kullanarak. – hpaulj

İlgili konular