2016-04-25 8 views
1

Ich benutze eine externe Bibliothek-Funktion, die eine numpy strukturierte Array zurückgibt.Spalte aus einem numpy strukturierten Array löschen (Liste der Tupel im Array)?

cities_array 
>>> array([ (1, [-122.46818353792992, 48.74387985436505], u'05280', u'Bellingham', u'53', u'Washington', u'5305280', u'city', u'N', -99, 52179), 
     (2, [-109.67985528815007, 48.54381826401885], u'35050', u'Havre', u'30', u'Montana', u'3035050', u'city', u'N', 2494, 10201), 
     (3, [-122.63068540357023, 48.49221584868184], u'01990', u'Anacortes', u'53', u'Washington', u'5301990', u'city', u'N', -99, 11451), 
     ..., 
     (3147, [-156.45657614262274, 20.870633142444376], u'22700', u'Kahului', u'15', u'Hawaii', u'1522700', u'census designated place', u'N', 7, 16889), 
     (3148, [-156.45038252004554, 20.76059218396], u'36500', u'Kihei', u'15', u'Hawaii', u'1536500', u'census designated place', u'N', -99, 11107), 
     (3149, [-155.08472452266503, 19.693112205773275], u'14650', u'Hilo', u'15', u'Hawaii', u'1514650', u'census designated place', u'N', 38, 37808)], 
     dtype=[('ID', '<i4'), ('Shape', '<f8', (2,)), ('CITY_FIPS', '<U5'), ('CITY_NAME', '<U40'), ('STATE_FIPS', '<U2'), ('STATE_NAME', '<U25'), ('STATE_CITY', '<U7'), ('TYPE', '<U25'), ('CAPITAL', '<U1'), ('ELEVATION', '<i4'), ('POP1990', '<i4')]) 

Die cities_array ist vom Typ <type 'numpy.ndarray'>.

Ich bin in der Lage einzelne Spalten des Arrays zuzugreifen:

cities_array[['ID','CITY_NAME']] 
>>> array([(1, u'Bellingham'), (2, u'Havre'), (3, u'Anacortes'), ..., 
     (3147, u'Kahului'), (3148, u'Kihei'), (3149, u'Hilo')], 
     dtype=[('ID', '<i4'), ('CITY_NAME', '<U40')]) 

Jetzt möchte ich die erste Spalte löschen, ID. Die help und SO questions sagen, es sollte numpy.delete sein.

Wenn dies ausgeführt wird: numpy.delete(cities_array,cities_array['ID'],1) ich die Fehlermeldung:

...in delete 
    N = arr.shape[axis] 
IndexError: tuple index out of range 

Was mache ich falsch? Soll ich das cities_array nachbearbeiten, um mit dem Array arbeiten zu können?

Ich bin auf Python 2.7.10 und numpy 1.11.0

+0

Wie in der Antwort gezeigt, können Sie eine Teilmenge der dtype-Namen anzeigen. Es ist kein echtes Löschen. Es gibt auch eine Bibliothek von recfuncs, die eine Löschkopie implementieren könnte. – hpaulj

+0

numpy.lib.recfunctions.drop_fields – hpaulj

+0

@hpaulj, danke für den Kommentar, gut zu wissen es gibt eine externe Bibliothek dafür. Aber ist es nicht seltsam, dass so eine grundlegende Operation fehlschlägt? Nur ein einfaches Array 'x = numpy.zeros (3, dtype = {'names': ['col1', 'col2'], 'formats': ['i4', 'f4']})' kann nicht löschen a Spalte mit 'numpy.delete (x, 0,1)'. Was ist der Grund für dieses Problem, irgendwelche Ideen? –

Antwort

2

Ich denke, dass dies funktionieren sollte:

def delete_colum(array, *args): 

    filtered = [x for x in array.dtype.names if x not in args] 

    return array[filtered] 

Beispiel mit Array:

a 
Out[9]: 
array([(1, [-122.46818353792992, 48.74387985436505])], 
     dtype=[('ID', '<i4'), ('Shape', '<f8', (2,))]) 

delete_colum(a,'ID') 
Out[11]: 
array([([-122.46818353792992, 48.74387985436505],)], 
     dtype=[('Shape', '<f8', (2,))]) 
1

Sie Kommentar:

Aber ist es nicht seltsam, dass solch eine grundlegende Operation f ails? Nur ein einfaches Array x = numpy.zeros(3, dtype={'names':['col1', 'col2'], 'formats':['i4','f4']}) kann eine Spalte mit numpy.delete(x,0,1) nicht löschen. Was ist der Grund für dieses Problem, irgendwelche Ideen?

np.delete ist keine grundlegende Operation. Schau dir den Code an. Es ist 5 Bildschirme lang (auf Ipython). Eine Menge davon behandelt die verschiedenen Möglichkeiten, wie Sie die Löschelemente angeben können.

Für np.delete (x, 0, Achse = 1)

es einen Sonderfall verwendet

# optimization for a single value 
    ... 
    newshape[axis] -= 1 
    new = empty(newshape, arr.dtype, arrorder) 
    slobj[axis] = slice(None, obj) 
    new[slobj] = arr[slobj] 
    slobj[axis] = slice(obj, None) 
    slobj2 = [slice(None)]*ndim 
    slobj2[axis] = slice(obj+1, None) 
    new[slobj] = arr[slobj2] 

für einen 2D-Array und Achse 1 = Funktion:

new = np.zeros((x.shape[0], x.shape[1]-1), dtype=x.dtype) 
new[:, :obj] = x[:, :obj] 
new[:, obj:] = x[:, obj+1:] 

Mit anderen Worten, es reserviert ein neues Array mit 1 weniger Spalte und kopiert dann zwei Scheiben vom Original zu ihm.

Mit mehreren Spalten löschen und boolean obj dauert es andere Routen.

Beachten Sie, dass für diese Aktion die Möglichkeit wichtig ist, die 2 Dimensionen zu indizieren.

Aber Sie können Ihre x auf diese Weise nicht indexieren. x[0,1] gibt einen too many indices Fehler. Sie müssen x[0]['col1'] verwenden. Die Indexierung der Felder eines dtype unterscheidet sich grundlegend von der Indizierung der Spalten eines 2d-Arrays.

Die recfunctions manipulieren die dtype Felder in Möglichkeiten, die normale numpy Funktionen nicht tun. Basierend auf früheren Studie, vermute ich, dass drop_field so etwas wie dies funktioniert:

In [57]: x # your x with some values 
Out[57]: 
array([(1, 3.0), (2, 2.0), (3, 1.0)], 
     dtype=[('col1', '<i4'), ('col2', '<f4')]) 

Ziel Array mit unterschiedlichen dtype (fehlt ein Feld)

In [58]: y=np.zeros(x.shape, dtype=x.dtype.descr[1:]) 

Kopie Werte, Feld für Feld:

In [60]: for name in y.dtype.names: 
    ...:  y[name]=x[name] 
In [61]: y 
Out[61]: 
array([(3.0,), (2.0,), (1.0,)], 
     dtype=[('col2', '<f4')]) 

Regelmäßige nd Indizierung wird um die Attribute shape und strides aufgebaut. Mit diesen (und der Bytegröße des Elements) kann die Position im Puffer data eines gewünschten Elements schnell identifiziert werden.

Mit einer Verbindung dtype arbeiten Form und Schritte auf die gleiche Weise, aber nbytes ist anders. In Ihrem Fall x ist es jeweils 24 - 12 für die Felder 10 und f4 Felder. Also regelmäßige Indexierungsschritte von einem 24-Bit-Datensatz zum nächsten. Um das 'col2'-Feld auszuwählen, muss daher der zweite Satz von 4 Bytes innerhalb jedes Datensatzes ausgewählt werden.

Wo es möglich ist, denke ich, dass es Feldauswahl in reguläre Indizierung übersetzt. __array_interface__ ist ein schönes Wörterbuch der wesentlichen Attribute eines Arrays.

In [70]: x.__array_interface__ 
Out[70]: 
{'data': (68826112, False), 
'descr': [('col1', '<i4'), ('col2', '<f4')], 
'shape': (3,), 
'strides': None, 
'typestr': '|V8', 
'version': 3} 

In [71]: x['col2'].__array_interface__ 
Out[71]: 
{'data': (68826116, False), 
'descr': [('', '<f4')], 
'shape': (3,), 
'strides': (8,), 
'typestr': '<f4', 
'version': 3} 

das zweite Array zeigt auf den gleichen Datenpuffer, aber 4 Bytes weiter entlang (der erste col2-Wert). In der Tat ist es eine Ansicht.

(np.transpose ist eine weitere Funktion, die nicht über die dtype Grenze funktioniert.)

===================

Hier ist der Code für drop_fields (zusammengefasst):

In [74]: from numpy.lib import recfunctions # separate import statement 
In [75]: recfunctions.drop_fields?? 

def drop_fields(base, drop_names, usemask=True, asrecarray=False): 
    .... # define `drop_descr function 
    newdtype = _drop_descr(base.dtype, drop_names) 
    output = np.empty(base.shape, dtype=newdtype) 
    output = recursive_fill_fields(base, output) 
    return output 

recursive_fill_fields hat einen Namen von Namensfeld zu kopieren, und in der Lage ist dtypes zu behandeln, die Felder innerhalb Felder (rekursiven Teil) definieren.

In [81]: recfunctions.drop_fields(x, 'col1') 
Out[81]: 
array([(3.0,), (2.0,), (1.0,)], 
     dtype=[('col2', '<f4')]) 

In [82]: x[['col2']] # multifield selection that David suggests 
Out[82]: 
array([(3.0,), (2.0,), (1.0,)], 
     dtype=[('col2', '<f4')]) 

In [83]: x['col2']  # single field view 
Out[83]: array([ 3., 2., 1.], dtype=float32) 

drop_field erzeugt ein ähnliches Ergebnis wie die Indizierung, die Mehrfelder @ David vorschlägt. Diese Multi-Indizierung ist jedoch nur wenig entwickelt, wie Sie sehen werden, wenn Sie irgendeine Art von Zuweisung versuchen.

Verwandte Themen