2012-03-14 17 views
8

Czy można skonstruować matrycę numpy z funkcji? W tym przypadku konkretnie funkcja jest absolutną różnicą dwóch wektorów: S[i,j] = abs(A[i] - B[j]). Minimalny przykład roboczych, które używa zwykłego pytona:Wypełnienie tablicy numpy z różnicy dwóch wektorów

import numpy as np 

A = np.array([1,3,6]) 
B = np.array([2,4,6]) 
S = np.zeros((3,3)) 

for i,x in enumerate(A): 
    for j,y in enumerate(B): 
     S[i,j] = abs(x-y) 

Dawanie:

[[ 1. 3. 5.] 
[ 1. 1. 3.] 
[ 4. 2. 0.]] 

Byłoby miło mieć konstrukcję, która wygląda mniej więcej tak:

def build_matrix(shape, input_function, *args) 

gdzie mogę zdać funkcja wejściowa z jej argumentami i zachowaj przewagę prędkości numpy.

+0

Jest to możliwe. Co próbujesz? – Marcin

+0

@Marcin - jak stwierdzono w pytaniu, używam zwykłego starego podejścia Pythona do wypełnienia matrycy już teraz. Przeglądanie dokumentacji numpy sugeruje, że funkcja 'wektoryzacji' może być użyteczna, ale nadal nie widziałem jak zbudować macierz z funkcji w pierwszej kolejności. Gdybyś mógł wskazać mi właściwy kierunek (z dokumentacją), byłbym wdzięczny! – Hooked

+0

To powinno być możliwe w zwykłym pythonie. Co próbujesz utworzyć swoją funkcję build_matrix? Na pewno coś masz i gdzieś tkwią, zamiast mieć nadzieję, że ktoś napisze to wszystko dla ciebie. – Marcin

Odpowiedz

10

Polecam przyjrzeniu do możliwości nadawania NumPy za:

In [6]: np.abs(A[:,np.newaxis] - B) 
Out[6]: 
array([[1, 3, 5], 
     [1, 1, 3], 
     [4, 2, 0]]) 

http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html

Następnie można po prostu napisać swoją funkcję jako:

In [7]: def build_matrix(func,args): 
    ...:  return func(*args) 
    ...: 

In [8]: def f1(A,B): 
    ...:  return np.abs(A[:,np.newaxis] - B) 
    ...: 

In [9]: build_matrix(f1,(A,B)) 
Out[9]: 
array([[1, 3, 5], 
     [1, 1, 3], 
     [4, 2, 0]]) 

To powinno być również znacznie szybciej niż rozwiązanie dla większych tablic.

+0

To jest idealne i ma znaczny wpływ na dużą liczbę N. Będę wyglądać bardziej na nadawanie, dziękuję. – Hooked

+2

Aby uniknąć tworzenia pośredniej tablicy, która zawiera różnicę, można użyć ['numpexpr'] (https://code.google.com/p/numexpr/):' c = a [:, Brak]; result = numexpr.valuate ("abs (c - b)") ' – jfs

+0

@ J.F.Sebastian - Dla każdego, co jest tego warte, możesz go również ominąć, biorąc bezwzględną wartość w miejscu, jeśli nie masz zainstalowanego' numexpr'. Jest jednak nieco bardziej gadatliwy: 'c = a [:, None]; wynik = c - b; np.abs (wynik, wynik) ' –

13

Oprócz tego, co zasugerował @JoshAdel, można również użyć parametru outer method dowolnego numpy ufunc, aby przeprowadzić emisję w przypadku dwóch tablic.

W tym przypadku po prostu chcesz np.subtract.outer(A, B) (lub raczej wartość bezwzględną).

Chociaż jeden z nich jest dość czytelny dla tego przykładu, w niektórych przypadkach nadawanie jest bardziej użyteczne, podczas gdy w innych przy użyciu metod ufunc jest czystszy.

Tak czy inaczej, warto znać obie sztuczki.

E.g.

import numpy as np 

A = np.array([1,3,6]) 
B = np.array([2,4,6]) 

diff = np.subtract.outer(A, B) 
result = np.abs(diff) 

Zasadniczo, można użyć outer, accumulate, reduce i reduceat z dowolnym numpy ufunc takich jak subtract, multiply, divide, a nawet takie rzeczy jak logical_and itp

Na przykład, np.cumsum jest równoważna do np.add.accumulate. Oznacza to, że możesz zaimplementować coś w stylu cumdiv przez np.divide.accumulate, nawet jeśli potrzebujesz.

+0

Dzięki @JoeKington, czy wiesz od ręki, czy istnieje jakaś wewnętrzna różnica między metodą emisji a zewnętrzną metodą? Dla praktyczności nie zauważam żadnej różnicy prędkości dla małych testów na moim komputerze, więc myślę, że mogę użyć jednego z nich. – Hooked

+0

@JoeKington +1 Zdecydowanie kolejny świetny zestaw numpy sztuczek, aby utrzymać swój rękaw. W niektórych przypadkach lubię to podejście lepiej, ponieważ uważam, że składnia jest bardziej opisowa. – JoshAdel

+1

@talonmies Na mojej maszynie do tablic z 10,100,1000 i 10000 elementów, nadawanie i metody zewnętrzne mają prawie taki sam czas, z metodą emisji wygraną niewielką ilością. – JoshAdel