2014-09-11 5 views
12

Ich verwende pandas Version 0.14.1 mit Python 2.7.5, und ich habe mit drei Spalten einen Datenrahmen, zB:Was ist die korrekte Syntax, um Spaltenwerte für ausgewählte Zeilen in einem Pandas-Datenrahmen mit nur einer Zeile zu vertauschen?

import pandas as pd 

d = {'L': ['left', 'right', 'left', 'right', 'left', 'right'], 
    'R': ['right', 'left', 'right', 'left', 'right', 'left'], 
    'VALUE': [-1, 1, -1, 1, -1, 1]} 
df = pd.DataFrame(d) 

idx = (df['VALUE'] == 1) 

Ergebnisse in einem Datenrahmen, die wie folgt aussieht:

 L  R VALUE 
0 left right  -1 
1 right left  1 
2 left right  -1 
3 right left  1 
4 left right  -1 
5 right left  1 

Für Zeilen, wo VALUE == 1, würde ich gerne den Inhalt der linken und rechten Spalten, so dass alle "links" Werte unter der "L" -Spalte, und die "richtigen" Werte enden unter der Spalte "R"

Nachdem sie bereits definiert die idx Variable oben, kann ich diese drei weitere Linien in nur leicht tun, indem Sie eine temporäre Variable wie folgt:

tmp = df.loc[idx,'L'] 
df.loc[idx,'L'] = df.loc[idx,'R'] 
df.loc[idx,'R'] = tmp 

aber dies scheint wie wirklich klobig und unförmig Syntax zu mir; sicherlich unterstützt pandas etwas prägnanter? Ich habe bemerkt, dass, wenn ich die Reihenfolge der Spalten in der Eingabe in den Datenrahmen .loc Attribut tauschen, dann erhalte ich die folgende tauschte Ausgabe:

In [2]: print(df.loc[idx,['R','L']]) 
     R  L 
1 left right 
3 left right 
5 left right 

Dies ist für mich schlägt vor, dass ich in der Lage sollte die gleiche Swap zu implementieren wie oben, nur um die folgende Zeile ein:

df.loc[idx,['L','R']] = df.loc[idx,['R','L']] 

jedoch, wenn ich dies tatsächlich versuchen, passiert nichts - die Spalten nicht vertauscht bleiben. Es ist, als ob Pandas automatisch erkennt, dass ich die Spalten in der falschen Reihenfolge auf der rechten Seite der Zuweisungsanweisung platziert habe, und es automatisch das Problem korrigiert. Gibt es eine Möglichkeit, dass ich diese "Spaltenreihenfolge-Autokorrektur" in Pandas-Zuweisungsanweisungen deaktivieren kann, um den Austausch zu implementieren, ohne unnötige temporäre Variablen zu erzeugen?

+0

Sieht man bei dataframe.eval? Sie haben ein Beispiel in Pandas docs: >>> df = Datenrahmen (randn (10, 2), Spalten = Liste ('ab')) >>> df.eval ('a + b') >>> df. eval ('c = a + b') – Rainy

+0

Für alle, die neugierig sind, habe ich eine Follow-up-Frage geschrieben: http://StackOverflow.com/Questions/25811529/setting-Values-on-a-subset-of-rows -indexing-boolean-setting – JohnE

Antwort

16

Eine Möglichkeit, die Ausrichtung auf Spaltennamen vermeiden könnte, würde über .values auf das zugrunde liegende Array fallen unten sein:

In [33]: df 
Out[33]: 
     L  R VALUE 
0 left right  -1 
1 right left  1 
2 left right  -1 
3 right left  1 
4 left right  -1 
5 right left  1 

In [34]: df.loc[idx,['L','R']] = df.loc[idx,['R','L']].values 

In [35]: df 
Out[35]: 
     L  R VALUE 
0 left right  -1 
1 left right  1 
2 left right  -1 
3 left right  1 
4 left right  -1 
5 left right  1 
+0

Dies scheint nur ordnungsgemäß zu funktionieren, wenn die Serie _idx_ dtype _bool_ hat. Wenn Ihre Serie die Werte 0/1 anstelle von True/False hat, konvertieren Sie mit 'idx.astype (bool)' zu dtype _bool_. – ashimashi

3

Der Schlüssel ist hier zu beachten ist, dass die Pandas Versuche automatisch Zeilen und Spalten ausrichten die Verwendung von Index- und Spaltennamen. Daher musst du Pandas irgendwie sagen, dass sie die Spaltennamen hier ignorieren sollen. Ein Weg ist wie @DSM, indem er in ein numpy Array konvertiert. Eine weitere Möglichkeit ist es, die Spalten umbenennen:

>>> df.loc[idx] = df.loc[idx].rename(columns={'R':'L','L':'R'}) 

     L  R VALUE 
0 left right  -1 
1 left right  1 
2 left right  -1 
3 left right  1 
4 left right  -1 
5 left right  1 
+0

Danke für Ihre Antwort; Ich habe DSM den Status "akzeptierte Antwort" gegeben, da er zuerst geantwortet hat, aber ich fand Ihre Antwort auch sehr hilfreich (und daher auch aufgewertet!). BTW, ich denke, es könnte einen Tippfehler in Ihrer ersten Methode geben; auf meinem System, mit Pandas 0.14.1 und Python 2.7.5, funktioniert es, wenn ich stattdessen einen Aufruf zu 'zip' hinzufüge; h., df.ix [idx, ['L', 'R']] = zip (df.ix [idx, 'R'], df.ix [idx, 'L']) '. Die zweite Methode funktioniert gut, also danke dafür! Für die dritte Methode glaube ich, dass das Problem darin besteht, dass das 'df [['R', 'L']] auf der rechten Seite 6 Zeilen lang ist, während das' df.loc [idx, ['L', 'R ']] 'ist nur 3 Zeilen. – stachyra

+0

Danke für die Rückmeldung. Methode 1 funktioniert für mich ohne den Reißverschluss (und auch wenn ich den Reißverschluss hinzufüge). Keine Ahnung, warum wir unterschiedliche Ergebnisse bekommen. Ich habe Pandas 14.1 und Python 2.7.7 (Anaconda-Distribution). Unter Windows 7 laufen. – JohnE

1

Sie können dies auch tun mit np.select und df.where i.e

Option 1: np.select

df[['L','R']] = pd.np.select(df['VALUE'] == 1, df[['R','L']].values, df[['L','R']].values) 

Option 2: df.where

df[['L','R']] = df[['R','L']].where(df['VALUE'] == 1, df[['L','R']].values) 

Option 3: df.mask

df[['L','R']] = df[['L','R']].mask(df['VALUE'] == 1, df[['R','L']].values) 

Ausgang:

L  R VALUE 
0 left right  -1 
1 left right  1 
2 left right  -1 
3 left right  1 
4 left right  -1 
5 left right  1 
Verwandte Themen