2016-04-12 6 views
0

Angenommen, ich habe folgendes numpy Array:Delegieren Anrufe zu einer Methode numpy Arrays auf dessen Elemente

arr = np.array(["a", "b", "c"], dtype=object) 

Jetzt möchte ich eine beliebige Funktion auszuführen, oder eine beliebige Methode aufrufen, auf jedem Element. Angenommen, ich möchte alle diese Elemente in Großbuchstaben setzen. „Logisch“ zu sprechen, würde Ich mag so etwas tun:

upp_arr = arr.upper() 

oder

upp_arr = str.upper(arr) 

Kurzversion: kann ich entweder die oben erreichen?

Lange Version: Das wird natürlich nicht arbeiten, um das Array unter Berücksichtigung nicht über eine upper Methode (auch wenn die einzelnen Elemente zu tun), noch die str Einbau-weiß, wie ein numpy Array zu behandeln. Ich möchte keine benutzerdefinierte Version von str.upper erstellen, die mit Arrays umgehen kann, da ich im Voraus wissen muss, welche Funktionen der Benutzer meines Arrays verwenden möchte.

Ich könnte so etwas wie

upp_arr = np.array([x.upper() for x in arr]) 

Ich mag das nicht tun, aber: jetzt muss ich an die Nutzer meines Codes belichten, dass arr tatsächlich ein numpy Array ist. Ich möchte etwas wie die oben genannten zwei nicht funktionierenden Lösungen bekommen.

ich versuchte, diese durch Nebenklassen np.ndarray und Überschreiben des __getattr__(self, name) Methode ein Array der Elemente -Attribut des Namens name geschehen zu lassen, wenn kein Attribut name von np.ndarray ist, und dessen __call__ Methode überschreiben, um ein Array der Elemente Aufruf `Ergebnis:

import numpy as np 

class MyArr(np.ndarray): 
    def __getattr__(self, name): 
     if hasattr(np.ndarray, name): 
      return getattr(np.ndarray, name) 
     arr = MyArr(self.shape, dtype=object) 
     arr[:] = [getattr(elem, name) for elem in self] 
     return arr 
    def __call__(self): 
     arr = MyArr(self.shape, dtype=self.dtype) 
     arr[:] = [elem() for elem in self] 
     return arr 

arr = MyArr((3,), dtype=object) 
arr[:] = ["a", "b", "c"] 
arr.upper() 

Dies hat zwei Probleme: die Array-Konstruktion ist ein Schmerz im Hintern (haben es instanziiert zuerst, und füllen sie ihn dann mit Werten) und Ich muss davon ausgehen, dass das Ergebnis o f Der Funktionsaufruf hat denselben D-Typ wie das ursprüngliche Array (dtype=self.dtype). Letzteres ist kein Problem, wenn ich bei object Typ Arrays bleiben, aber im Allgemeinen werden.

Wie lösen?

+0

Ich sehe das Problem mit Konstrukt und Füllung nicht. 'numpy' macht das die ganze Zeit. 'vectorize' wertet einen Wert aus und verwendet sein Ergebnis, um den Rückgabe-dtype festzulegen. Gelegentlich ergeben sich SO-Fragen. – hpaulj

Antwort

-1

Es gibt eine Bibliothek von Funktionen, die str Operationen auf die Elemente eines String-Arrays, z.

In [199]: np.char.upper(np.array(['a','b','c'])) 
Out[199]: 
array(['A', 'B', 'C'], 
     dtype='|S1') 

Aber es funktioniert nicht auf Anordnungen von dtype Objekt:

In [200]: np.char.upper(np.array(['a','b','c'],dtype=object)) 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-200-17a9e3cc581f> in <module>() 
----> 1 np.char.upper(np.array(['a','b','c'],dtype=object)) 
...\numpy\core\defchararray.pyc in upper(a) 
    1571  """ 
    1572  a_arr = numpy.asarray(a) 
-> 1573  return _vec_string(a_arr, a_arr.dtype, 'upper') 
TypeError: string operation on non-string array 

Aber diese char Funktion ist nicht schneller als das entsprechende Liste Verständnis. Es muss immer noch die str-Operation für jedes Element aufrufen. Aber es ist bequemer, wenn das Array n-d ist.

In [209]: timeit np.char.upper(x1) # large x1 
1000 loops, best of 3: 277 µs per loop 

In [210]: timeit np.array([i.upper() for i in x1]) 
1000 loops, best of 3: 278 µs per loop 

Ein paar neuen Gedanken zu diesem Thema.

np.frompyfunc wendet eine Funktion auf alle Elemente eines Arrays an und gibt ein neues Objekttyp-Array zurück.

In [49]: vupper = np.frompyfunc(lambda astr: astr.upper(), 1, 1) 
In [50]: vupper(np.array(['a','b','c'])) 
Out[50]: array(['A', 'B', 'C'], dtype=object) 
In [51]: vupper(np.array(['a','b','c'], dtype=object)) 
Out[51]: array(['A', 'B', 'C'], dtype=object) 

np.vectorize verwendet np.frompyfunc, aber fügt einige dtype Konvertierung. In meinen Tests ist np.frompyfunc ein bisschen schneller; in einigen Fällen 2x schneller als eine äquivalente Listenverständnisversion.

Betrachten Sie numpy/core/records.py, um zu sehen, wie np.recarray uns strukturierte Array-Felder als Attribute zugreifen lässt. Es umhüllt __getattribute__.

Maskierte Arrays sind ein gutes Beispiel für eine Array-Unterklasse, die über eine große Sammlung von benutzerdefinierten Methoden verfügt. /numpy/ma/__init__.py

+0

Das ist immer noch nur eine bestimmte Reihe von Funktionen. Ich suche nach einer Lösung, die mit _any_ Funktion arbeitet. – acdr