2012-07-05 13 views
6

Mam numpy.array s gdzie kolumny zawierają różne typy danych, a kolumny powinny również mieć przypisane do nich różne funkcje. Mam również funkcje w tablicy.Numpy: Zastosuj tablicę funkcji do tej samej długości tablicy 2d, jak gdyby pomnożono elementwise? (przy użyciu funkcji Pythona jako operatora?)

Powiedzmy:

a = array([[ 1, 2.0, "three"], 
      [ 4, 5.0, "six" ]], dtype=object) 

functions_arr = array([act_on_int, act_on_float, act_on_str]) 

pewnością mogę myśleć sposobów, aby to zrobić poprzez podzielenie rzeczy, ale jedna rzecz, która wydaje się najbardziej naturalne, aby mi to myśleć o nim jako mnożenie elementwise z nadawania, i funkcje jako operatorzy. Więc chciałbym zrobić coś takiego

functions_arr*a 

i uzyskać efekt

array([[act_on_int(1), act_on_float(2.0), act_on_str("three")], 
     [act_on_int(4), act_on_float(5.0), act_on_str("six") ]]) 

Czy znasz sposób, aby osiągnąć coś w tym kierunku?

Edit: Zmieniłem definicji tablicy w kwestii zawierać dtype=[object] jak ludzie wskazał, to jest ważne dla tablica do przechowywania Rodzaje sposób zamierzałem.

Dziękuję za odpowiedzi i komentarze! Przyjąłem odpowiedź senderles i czuję, że jest to bardzo zbliżone do tego, co miałem na myśli.

Ponieważ nie wydaje się być pewne zamieszanie o tym, jak uważam operację być jak mnożenie, pozwól mi wyjaśnić, że z innym przykład:

Jak jesteś w pełni świadoma, operacja jak:

v = array([1,2,3]) 
u = array([[5,7,11], 
      [13,17,19]]) 
v*u 

będzie nadawać v nad rzędami u i daje

array([[ 1*5, 2*7, 3*11], 
     [1*13, 2*17, 3*19]]) 

tj

array([[ 5, 14, 33], 
     [13, 34, 57]]) 

Gdybyśmy teraz mieli zastąpić v z na przykład del operator musielibyśmy (po to nie rzeczywiście działa kodu Pythona :)

V = array([(d/dx),(d/dy),(d/dz)]) 
u = array([[5,7,11], 
      [13,17,19]]) 
V*u 

otrzymując (w duchu)

array([[(d/dx)5, (d/dy)7, (d/dz)11]], 
     [(d/dx)13,(d/dy)17,(d/dz)19]]) 

Przyznaję, że przyjęcie pochodnej kilku stałych nie byłoby najbardziej Ciekawe operacje, więc możesz zastąpić u pewnym symbolicznym wyrażeniem matematycznym w x, y i z. W każdym razie mam nadzieję, że to przynajmniej bardziej wyjaśnia zarówno moje rozumowanie, jak i nieco o "(używając funkcji Pythona jako operatora?)" W tytule.

Odpowiedz

2

Jak Sven Marnach przypomniał mi, utworzonych wcześniej tablica jest prawdopodobnie tablicą obiektów Pythona. Każda operacja na nich będzie prawdopodobnie znacznie wolniejsza niż czysta operacja numpy. Możesz jednak łatwo wykonać to, o co prosiłeś, o ile nie spodziewasz się, że będzie to bardzo szybkie! To nie jest zbyt różni się od tego, co AFoglia zasugerował, ale bliżej jest dokładnie to, co prosiłeś:

>>> a = numpy.array([[ 1, 2.0, "three"], 
...     [ 4, 5.0, "six" ]], dtype=object) 
>>> funcs = [lambda x: x + 10, lambda x: x/2, lambda x: x + '!'] 
>>> apply_vectorized = numpy.vectorize(lambda f, x: f(x), otypes=[object]) 
>>> apply_vectorized(funcs, a) 
array([[11, 1.0, three!], 
     [14, 2.5, six!]], dtype=object) 

echem także AFoglia tutaj, istnieje duża szansa, że ​​będziesz lepiej wyłączyć za pomocą tablicy rekord - to pozwala można podzielić tablicę się jak chcesz, i pracować z nim w bardziej naturalny sposób za pomocą numpy ufuncs - które są znacznie szybsze niż funkcje Pythona, ogólnie:

rec.array([(1, 2.0, 'three'), (4, 5.0, 'six')], 
     dtype=[('int', '<i8'), ('float', '<f8'), ('str', '|S10')]) 
>>> a['int'] 
array([1, 4]) 
>>> a['float'] 
array([ 2., 5.]) 
>>> a['str'] 
rec.array(['three', 'six'], 
     dtype='|S10') 
>>> a['int'] += 10 
>>> a['int'] 
array([11, 14]) 
3

szukasz wbudowanej funkcji zip()

Prosty przykład stosując lists:

>>> a=[[ 1, 2.0, "three"],[ 4, 5.0, "six" ]] 

>>> funcs=[lambda x:x**2,lambda y:y*2,lambda z:z.upper()] 

>>> [[f(v) for v,f in zip(x,funcs)]for x in a] 
[[1, 4.0, 'THREE'], [16, 10.0, 'SIX']] 
+3

nie sądzę, to jest odpowiedź na pytanie. OP zapytał, jak uzyskać nadawanie w tej sytuacji. Ten kod nie transmituje. –

3

To nie nadawania, ponieważ oryginalna tablica miała tylko jeden wymiar. Wygląda na to, że ma 2 wymiary, ponieważ każdy element ma trzy elementy (int, float i string), ale na numpy, to po prostu typ, a liczba wymiarów to jeden.

Nie jest także mnożeniem, ponieważ stosujesz funkcję do każdego elementu. (To nie jest więcej mnożenia niż dodawanie, więc functions_arr * a jest mylącą składnią).

Mimo to możesz napisać coś analogicznego do tego, co chcesz. Chciałbym spróbować numpy.vectorize. Bez testowania go i zakładając, że wyjściowy typ dtype jest taki sam jak oryginalna tablica. Wyobrażam sobie, że tak będzie ...

def act_on_row(row) : 
    return (act_on_int(row["int_field"]), 
      act_on_float(row["float_field"]), 
      act_on_str(row["str_field"])) 

act_on_array = numpy.vectorize(act_on_row, otypes=[a.dtype]) 

acted_on = act_on_array(a) 

Nigdy nie próbowałem wektoryzacji, a ja nie wiem, czy to jest trudne, aby dostać pracę z dtypes strukturyzowanych, ale to powinno Ci zacząć.

Jednak prostszym rozwiązaniem byłoby po prostu przelokowanie tablicy po polu.

rslt = numpy.empty((len(a),), dtype=a.dtype) 

rslt["int_field"] = act_on_int(a["int_field"]) 
rslt["float_field"] = act_on_float(a["float_field"]) 
rslt["str_field"] = act_on_str(a["str_field"]) 

(Być może trzeba wektorować poszczególnych funkcji, w zależności od tego, co robią.)

+1

Macierz 'a' zdefiniowana w oryginalnym wpisie to dwuwymiarowa tablica, a * nie * jednowymiarowa uporządkowana tablica. (Można argumentować, że OP * powinien * faktycznie używać tablicy strukturalnej). –

+0

@SvenMarnach, zgadza się; ale czy jest nawet możliwe, aby mieć prawdziwie dwuwymiarową tablicę z heterogenicznymi typami danych? Miałem zamiar zaproponować wariację na temat tej odpowiedzi, ale nie mogłem pojąć, jak stworzyć to, co OP twierdzi, że stworzyło. W tym celu użyłem tylko tablic strukturalnych/rekordów. – senderle

+1

@senderle: Myślę, że kod podany przez OP po prostu utworzy tablicę ciągów o stałej szerokości. Możesz utworzyć heterogeniczną tablicę za pomocą 'dtype = object', która pozwala dowolnie ustawić obiekty Pythona jako elementy tablicy. Jednak spowoduje to unieważnienie większości wydajności i zalet pamięci NumPy - takie tablice można opisać jako wielowymiarowe listy o stałej wielkości Pythona. –

Powiązane problemy