2017-03-14 11 views
2

Arrays 'A' und Vektor 'B' sind Teil des Pandas Datenrahmens.Vergleichen Sie eine Matrix mit einem Spaltenvektor

Ich habe ein großes Array A der Form:

28 39 52 
77 80 66 
7 18 24 
9 97 68 

ich einen Vektor B von Form haben:

32 
5 
42 
17 

Wie vergleiche ich pythonically jede Spalte von A gegen B. Ich versuche, um Wahr/Falsch-Werte für A < B Vergleich zu erhalten, um das folgende Ergebnis zu erhalten:

TRUE FALSE FALSE 
FALSE FALSE FALSE 
TRUE TRUE TRUE 
TRUE FALSE FALSE 

Ich kann Listenverständnis Syntax tun, aber gibt es einen besseren Weg, um dies zu ziehen. Mein Array A und B sind sehr groß.

Antwort

7

Betrachten Sie die pd.DataFrame und pd.Series, A und B

A = pd.DataFrame([ 
     [28, 39, 52], 
     [77, 80, 66], 
     [7, 18, 24], 
     [9, 97, 68] 
    ]) 

B = pd.Series([32, 5, 42, 17]) 

pandas

standardmäßig, wenn Sie eine pd.DataFrame mit pd.Series, Pandas ausrichtet vergleichen jeder Indexwert aus der Reihe mit den Spaltennamen des Datenrahmens. Dies passiert, wenn Sie A < B verwenden. In diesem Fall haben Sie 4 Zeilen in Ihrem Datenframe und 4 Elemente in Ihrer Serie, also gehe ich davon aus, dass Sie die Indexwerte der Serie an die Indexwerte des Datenrahmens anpassen wollen. Um die Achse anzugeben, an der Sie ausrichten möchten, müssen Sie die Vergleichsmethode und nicht den Operator verwenden. Wenn Sie die Methode verwenden, können Sie den axis-Parameter verwenden und angeben, dass Sie lieber axis=0 als den Standard axis=1 möchten.

A.lt(B, axis=0) 

     0  1  2 
0 True False False 
1 False False False 
2 True True True 
3 True False False 

ich oft nur schreiben dies als A.lt(B, 0)


numpy

In numpy, man muss auch die Aufmerksamkeit auf die Dimensionalität der Arrays zahlen und Sie davon aus, dass Die Positionen sind bereits aufgereiht. Die Positionen werden berücksichtigt, wenn sie aus demselben Datenrahmen stammen.

print(A.values) 

[[28 39 52] 
[77 80 66] 
[ 7 18 24] 
[ 9 97 68]] 

print(B.values) 

[32 5 42 17] 

Hinweis, dass B ist ein 1-dimensionales Array, während A ein 2-dimensionales Array ist. Um B entlang der Zeilen von A zu vergleichen, müssen wir B in ein zweidimensionales Array umformen. Der offensichtlichste Weg, dies zu tun, ist mit reshape

print(A.values < B.values.reshape(4, 1)) 

[[ True False False] 
[False False False] 
[ True True True] 
[ True False False]] 

Diese sind jedoch Möglichkeiten, in denen Sie häufig andere sehen das gleiche tun

A.values < B.values.reshape(-1, 1) 

Oder

A.values < B.values[:, None] 

Umformung

zeitgesteuerter Test

Um zu verstehen, wie schnell diese Vergleiche sind, habe ich den folgenden Backtest konstruiert.

def pd_cmp(df, s): 
    return df.lt(s, 0) 

def np_cmp_a2a(df, s): 
    """To get an apples to apples comparison 
    I return the same thing in both functions""" 
    return pd.DataFrame(
     df.values < s.values[:, None], 
     df.index, df.columns 
    ) 

def np_cmp_a2o(df, s): 
    """To get an apples to oranges comparison 
    I return a numpy array""" 
    return df.values < s.values[:, None] 


results = pd.DataFrame(
    index=pd.Index([10, 1000, 100000], name='group size'), 
    columns=pd.Index(['pd_cmp', 'np_cmp_a2a', 'np_cmp_a2o'], name='method'), 
) 

from timeit import timeit 

for i in results.index: 
    df = pd.concat([A] * i, ignore_index=True) 
    s = pd.concat([B] * i, ignore_index=True) 
    for j in results.columns: 
     results.set_value(
      i, j, 
      timeit(
       '{}(df, s)'.format(j), 
       'from __main__ import {}, df, s'.format(j), 
       number=100 
      ) 
     ) 

results.plot() 

enter image description here

ich, dass die schnellen numpy basierten Lösungen schließen kann, aber alles, was nicht viel. Sie alle skalieren gleich.

+0

Da OP sagt, dass die Arrays sehr groß sind, würde Leistungsvergleich b/w Pandas vs Numpy für zukünftige Leser sehr informativ sein – kmario23

+1

@ kmario23 Ich habe meinen Beitrag mit Timings – piRSquared

+1

aktualisiert Ich mag wirklich Ihre Pandas "Zeit" Wrapper. – MaxU

3

Je effizienter ist numpy Ebene zu gehen (A, B sind Datenrahmen hier):

A.values<B.values 
3

Sie können dies mit lt tun und ruft squeeze auf B so flacht es die df zu einem 1-D Serie:

In [107]: 
A.lt(B.squeeze(),axis=0) 

Out[107]: 
     0  1  2 
0 True False False 
1 False False False 
2 True True True 
3 True False False 

Das Problem ist, dass ohne squeeze dann wird es versuchen, auf den Spaltenbeschriftungen nicht ausgerichtet, die wir nicht wollen. Wir wollen

den Vergleich entlang der Spalte-Achse übertragen
1

Eine weitere Option numpy verwendet, ist mit numpy.newaxis

In [99]: B = B[:, np.newaxis] 

In [100]: B 
Out[100]: 
array([[32], 
     [ 5], 
     [42], 
     [17]]) 

In [101]: A < B 
Out[101]: 
array([[ True, False, False], 
     [False, False, False], 
     [ True, True, True], 
     [ True, False, False]], dtype=bool) 

Im Wesentlichen sind die Umwandlung wir den Vektor B in eine 2D-Array, so dass numpy übertragen kann, wenn zwei Arrays von verschiedenen Formen zu vergleichen.

+1

das ist nützlich, wusste nicht über np.newaxis +1 – EdChum

+0

@EdChum 'np.newaxis' ist auch mit' None'. 'np.newaxis ist keine' ergibt 'True' – piRSquared

+0

@piRSquared ah .. Ich wusste das nicht, ich habe immer 'None' in diesen Situationen – EdChum

Verwandte Themen