2013-10-03 10 views
5

Ich versuche, die folgende Anordnung auf column1 zu sortieren, dann column2 und dann column3Sortierung numpy Array auf mehrere Spalten in Python

[['2008' '1' '23' 'AAPL' 'Buy' '100'] 
['2008' '1' '30' 'AAPL' 'Sell' '100'] 
['2008' '1' '23' 'GOOG' 'Buy' '100'] 
['2008' '1' '30' 'GOOG' 'Sell' '100'] 
['2008' '9' '8' 'GOOG' 'Buy' '100'] 
['2008' '9' '15' 'GOOG' 'Sell' '100'] 
['2008' '5' '1' 'XOM' 'Buy' '100'] 
['2008' '5' '8' 'XOM' 'Sell' '100']] 

ich den folgenden Code verwendet:

idx=np.lexsort((order_array[:,2],order_array[:,1],order_array[:,0])) 
    order_array=order_array[idx] 

Das resultierende Array ist

[['2008' '1' '23' 'AAPL' 'Buy' '100'] 
['2008' '1' '23' 'GOOG' 'Buy' '100'] 
['2008' '1' '30' 'AAPL' 'Sell' '100'] 
['2008' '1' '30' 'GOOG' 'Sell' '100'] 
['2008' '5' '1' 'XOM' 'Buy' '100'] 
['2008' '5' '8' 'XOM' 'Sell' '100'] 
['2008' '9' '15' 'GOOG' 'Sell' '100'] 
['2008' '9' '8' 'GOOG' 'Buy' '100']] 

Das Problem ist, dass die letzten zwei Zeilen falsch sind. Das richtige Array sollte die letzte Zeile als vorletzte haben. Ich habe alles versucht, aber ich verstehe nicht, warum das passiert. Ich werde einige Hilfe zu schätzen wissen.

Ich verwende den folgenden Code zum Abrufen von order_array.

+0

möglich Duplikat [Sortieren einer 2D numpy Array von mehreren Achsen] (http://stackoverflow.com/questions/2706605/sorting-a-2d-numpy-array-by-multiple -axes) Verwenden Sie diese Antwort, aber verwenden Sie einen dtype, der für Ihre Daten (nicht alle Strings) sinnvoll ist, z 'dt = dt = [('y', np.uint32), ('m', np.uint32), ('d', np.uint32), ('sym', 'S4'), ('bs' , 'S4'), ('huh', np.uint32)] ' – askewchan

Antwort

7

tldr: NumPy scheint, wenn numerische Berechnungen auf numerischen Arrays durchgeführt werden. Obwohl es möglich ist (siehe unten), ist NumPy dafür nicht gut geeignet. Sie sind wahrscheinlich besser dran mit Pandas.


Die Ursache des Problems:

Die Werte als Strings sortiert werden. Sie müssen sie als ints sortieren.

Dies passierte, weil order_array Strings enthält. Sie müssen diese Zeichenfolgen gegebenenfalls in ints konvertieren.

Das Konvertieren von Dtypes von String-dtype in numerisch dtype erfordert die Zuweisung von Speicherplatz für ein neues Array. Daher wäre es wahrscheinlich besser, die Art, wie Sie order_array von Anfang an erstellen, zu überarbeiten.

Interessanterweise, obwohl Sie die Werte ints umgewandelt, wenn Sie

order_array = np.array(rows_list) 

NumPy standardmäßig Aufruf erzeugt ein homogenes Array. In einem homogenen Array hat jeder Wert den gleichen dtype. Also versuchte NumPy, den gemeinsamen Nenner unter all Ihren Werten zu finden und wählte einen String dtype, der den Aufwand, den Sie in die Umwandlung der Strings in Ints setzen, vereitelt!

Sie können die dtype für sich selbst überprüfen, indem order_array.dtype Inspektion:

In [42]: order_array = np.array(rows_list) 

In [43]: order_array.dtype 
Out[43]: dtype('|S4') 

Nun, wie beheben wir das?


ein Objekt dtype Verwendung:

Der einfachste Weg ist es, ein 'Objekt' dtype

In [53]: order_array = np.array(rows_list, dtype='object') 

In [54]: order_array 
Out[54]: 
array([[2008, 1, 23, AAPL, Buy, 100], 
     [2008, 1, 30, AAPL, Sell, 100], 
     [2008, 1, 23, GOOG, Buy, 100], 
     [2008, 1, 30, GOOG, Sell, 100], 
     [2008, 9, 8, GOOG, Buy, 100], 
     [2008, 9, 15, GOOG, Sell, 100], 
     [2008, 5, 1, XOM, Buy, 100], 
     [2008, 5, 8, XOM, Sell, 100]], dtype=object) 

Das Problem hier zu verwenden ist, dass np.lexsort oder np.sort funktionieren nicht auf Anordnungen von dtype object. Um das zu umgehen dieses Problem, könnte man die rows_list sortieren, bevor die Schaffung order_list:

In [59]: import operator 

In [60]: rows_list.sort(key=operator.itemgetter(0,1,2)) 
Out[60]: 
[(2008, 1, 23, 'AAPL', 'Buy', 100), 
(2008, 1, 23, 'GOOG', 'Buy', 100), 
(2008, 1, 30, 'AAPL', 'Sell', 100), 
(2008, 1, 30, 'GOOG', 'Sell', 100), 
(2008, 5, 1, 'XOM', 'Buy', 100), 
(2008, 5, 8, 'XOM', 'Sell', 100), 
(2008, 9, 8, 'GOOG', 'Buy', 100), 
(2008, 9, 15, 'GOOG', 'Sell', 100)] 

order_array = np.array(rows_list, dtype='object') 

Eine bessere Möglichkeit wäre, die ersten drei Spalten in datetime.date Objekte zu kombinieren:

import operator 
import datetime as DT 

for i in ...: 
    seq = [DT.date(int(x.year), int(x.month), int(x.day)) ,s_sym, 'Buy', 100] 
    rows_list.append(seq) 
rows_list.sort(key=operator.itemgetter(0,1,2))   
order_array = np.array(rows_list, dtype='object') 

In [72]: order_array 
Out[72]: 
array([[2008-01-23, AAPL, Buy, 100], 
     [2008-01-30, AAPL, Sell, 100], 
     [2008-01-23, GOOG, Buy, 100], 
     [2008-01-30, GOOG, Sell, 100], 
     [2008-09-08, GOOG, Buy, 100], 
     [2008-09-15, GOOG, Sell, 100], 
     [2008-05-01, XOM, Buy, 100], 
     [2008-05-08, XOM, Sell, 100]], dtype=object) 

Auch wenn diese ist einfach, ich mag keine NumPy Arrays von dtype Objekt. Sie erhalten weder die Geschwindigkeit noch die Speicherplatzersparnis von NumPy-Arrays mit nativen dtypes. An dieser Stelle könnte es sein, dass Sie mit einer Python-Liste von Listen schneller und syntaktisch leichter umgehen können.


ein strukturiertes Array:

Eine NumPy-Ish-Lösung, die nach wie vor Vorteile Geschwindigkeit und Speicher bietet, ist eine structured array zu verwenden (im Gegensatz zu homogenen Array). Um ein strukturierten Array zu machen mit np.array Sie benötigen eine dtype explizit liefern:

dt = [('year', '<i4'), ('month', '<i4'), ('day', '<i4'), ('symbol', '|S8'), 
     ('action', '|S4'), ('value', '<i4')] 
order_array = np.array(rows_list, dtype=dt) 

In [47]: order_array.dtype 
Out[47]: dtype([('year', '<i4'), ('month', '<i4'), ('day', '<i4'), ('symbol', '|S8'), ('action', '|S4'), ('value', '<i4')]) 

Um die strukturierte Array sortieren könnten Sie die sort Methode verwenden:

order_array.sort(order=['year', 'month', 'day']) 

Für die Arbeit mit strukturierten Arrays müssen Sie einige Unterschiede zwischen homogenen und strukturierten Arrays kennen:

Ihr Original die homogene Anordnung war zweidimensional. Dagegen sind alle strukturierte Arrays sind 1-dimensional:

In [51]: order_array.shape 
Out[51]: (8,) 

Wenn Sie Index die strukturierte Anordnung mit einem int oder das Array durchlaufen, Sie Zeilen zurück:

In [52]: order_array[3] 
Out[52]: (2008, 1, 30, 'GOOG', 'Sell', 100) 

Mit homogenen Arrays Sie können auf die Spalten mit order_array[:, i] zugreifen Nun, mit einem strukturierten Array, greifen Sie auf sie mit Namen: z order_array['year'].


Oder verwenden Sie Pandas:

Wenn Sie Pandas installieren können, ich denke, könnten Sie am glücklichsten Arbeits mit Pandas Datenrahmen sein:

In [73]: df = pd.DataFrame(rows_list, columns=['date', 'symbol', 'action', 'value']) 
In [75]: df.sort(['date']) 
Out[75]: 
     date symbol action value 
0 2008-01-23 AAPL Buy 100 
2 2008-01-23 GOOG Buy 100 
1 2008-01-30 AAPL Sell 100 
3 2008-01-30 GOOG Sell 100 
6 2008-05-01 XOM Buy 100 
7 2008-05-08 XOM Sell 100 
4 2008-09-08 GOOG Buy 100 
5 2008-09-15 GOOG Sell 100 

Pandas hat nützliche Funktionen für Zeitreihen Ausrichten nach Datum, fehlende Angabe Werte, gruppieren und aggregieren/transformieren Zeilen oder Spalten.

In der Regel ist es sinnvoller, eine einzige Datumsspalte anstelle von drei ganzzahligen Spalten für das Jahr, den Monat und den Tag zu verwenden.

Wenn Sie das Jahr, den Monat, den Tag als separate Spalten für die Zwecke der outputing benötigen, zu sagen, csv, dann können Sie die Datumsspalte mit Jahr, Monat, Tag Spalten wie folgt ersetzen:

In [33]: df = df.join(df['date'].apply(lambda x: pd.Series([x.year, x.month, x.day], index=['year', 'month', 'day']))) 

In [34]: del df['date'] 

In [35]: df 
Out[35]: 
    symbol action value year month day 
0 AAPL Buy 100 2008  1 23 
1 GOOG Buy 100 2008  1 23 
2 AAPL Sell 100 2008  1 30 
3 GOOG Sell 100 2008  1 30 
4 XOM Buy 100 2008  5 1 
5 XOM Sell 100 2008  5 8 
6 GOOG Buy 100 2008  9 8 
7 GOOG Sell 100 2008  9 15 

Wenn Sie die Spalte "Datum" nicht verwenden, können Sie natürlich rows_list allein lassen und den DataFrame mit den Spalten Jahr, Monat und Tag von Anfang an erstellen. Das Sortieren ist immer noch einfach:

df.sort(['year', 'month', 'day']) 
+0

danke. aber ich konvertiere die Strings nach int. Ich habe die Frage bearbeitet, um den Code zum Erstellen von order_array einzuschließen. freuen Sie sich auf Ihre Hilfe – user2842122

+0

@ user2842122 - diese 'Ints' werden wieder in Strings konvertiert. unutbu - Ich denke, die einfachste Lösung könnte hier die Einführung eines NumPy-Recarrays sein, das aus einem NumPy [datetime object] (http://docs.scipy.org/doc/numpy/reference/arrays.datetime.html) und Ihren verbleibenden Komponenten besteht String- und Integer-Daten. Es gibt [ein vollständiges Beispiel hier] (http://stackoverflow.com/a/16618557/122022). –

+0

@AronAhmadia: Vielen Dank für den Kommentar! Ja, ich dachte daran, etwas hinzuzufügen, aber ich fürchte, diese Antwort ist schon zu lang und Pandas ist immer noch der bessere Weg. – unutbu

Verwandte Themen