it-swarm.com.de

Auswahl mit komplexen Kriterien aus pandas.DataFrame

Zum Beispiel habe ich einfache DF:

import pandas as pd
from random import randint

df = pd.DataFrame({'A': [randint(1, 9) for x in xrange(10)],
                   'B': [randint(1, 9)*10 for x in xrange(10)],
                   'C': [randint(1, 9)*100 for x in xrange(10)]})

Kann ich Werte aus 'A' auswählen, für die entsprechende Werte für 'B' größer als 50 sind, und für 'C' - ungleich 900 - mit Methoden und Idiomen von Pandas?

157
Gill Bates

Sicher! Konfiguration:

>>> import pandas as pd
>>> from random import randint
>>> df = pd.DataFrame({'A': [randint(1, 9) for x in range(10)],
                   'B': [randint(1, 9)*10 for x in range(10)],
                   'C': [randint(1, 9)*100 for x in range(10)]})
>>> df
   A   B    C
0  9  40  300
1  9  70  700
2  5  70  900
3  8  80  900
4  7  50  200
5  9  30  900
6  2  80  700
7  2  80  400
8  5  80  300
9  7  70  800

Wir können Spaltenoperationen anwenden und boolesche Serienobjekte erhalten:

>>> df["B"] > 50
0    False
1     True
2     True
3     True
4    False
5    False
6     True
7     True
8     True
9     True
Name: B
>>> (df["B"] > 50) & (df["C"] == 900)
0    False
1    False
2     True
3     True
4    False
5    False
6    False
7    False
8    False
9    False

[Update, um zum neuen Stil .loc zu wechseln]:

Und dann können wir diese verwenden, um das Objekt zu indizieren. Für den Lesezugriff können Sie Indizes verketten:

>>> df["A"][(df["B"] > 50) & (df["C"] == 900)]
2    5
3    8
Name: A, dtype: int64

sie können sich jedoch wegen des Unterschieds zwischen einer Ansicht und einer Kopie, die dies für den Schreibzugriff tut, in Schwierigkeiten bringen. Sie können stattdessen .loc verwenden:

>>> df.loc[(df["B"] > 50) & (df["C"] == 900), "A"]
2    5
3    8
Name: A, dtype: int64
>>> df.loc[(df["B"] > 50) & (df["C"] == 900), "A"].values
array([5, 8], dtype=int64)
>>> df.loc[(df["B"] > 50) & (df["C"] == 900), "A"] *= 1000
>>> df
      A   B    C
0     9  40  300
1     9  70  700
2  5000  70  900
3  8000  80  900
4     7  50  200
5     9  30  900
6     2  80  700
7     2  80  400
8     5  80  300
9     7  70  800

Beachten Sie, dass ich aus Versehen == 900 und nicht != 900 oder ~(df["C"] == 900) eingegeben habe. Übung für den Leser. : ^)

276
DSM

Eine andere Lösung ist die Verwendung der query -Methode:

import pandas as pd

from random import randint
df = pd.DataFrame({'A': [randint(1, 9) for x in xrange(10)],
                   'B': [randint(1, 9) * 10 for x in xrange(10)],
                   'C': [randint(1, 9) * 100 for x in xrange(10)]})
print df

   A   B    C
0  7  20  300
1  7  80  700
2  4  90  100
3  4  30  900
4  7  80  200
5  7  60  800
6  3  80  900
7  9  40  100
8  6  40  100
9  3  10  600

print df.query('B > 50 and C != 900')

   A   B    C
1  7  80  700
2  4  90  100
4  7  80  200
5  7  60  800

Wenn Sie nun die zurückgegebenen Werte in Spalte A ändern möchten, können Sie ihren Index speichern:

my_query_index = df.query('B > 50 & C != 900').index

.... und benutze .iloc, um sie zu ändern.

df.iloc[my_query_index, 0] = 5000

print df

      A   B    C
0     7  20  300
1  5000  80  700
2  5000  90  100
3     4  30  900
4  5000  80  200
5  5000  60  800
6     3  80  900
7     9  40  100
8     6  40  100
9     3  10  600
37

Sie können pandas es hat einige eingebaute Funktionen zum Vergleich. Wenn Sie also Werte von "A" auswählen möchten, die durch die Bedingungen von "B" und "C" erfüllt werden (vorausgesetzt Sie) möchte einen DataFrame zurück pandas object)

df[['A']][df.B.gt(50) & df.C.ne(900)]

df[['A']] gibt die Spalte A im DataFrame-Format zurück.

die Funktion pandas 'gt' gibt die Positionen von Spalte B zurück, die größer als 50 sind, und 'ne' gibt die Positionen ungleich 900 zurück.

Und denken Sie daran, Klammern zu verwenden!

Beachten Sie, dass der Operator & Vorrang vor Operatoren wie > oder < usw. hat

4 < 5 & 6 > 4

wird zu False ausgewertet. Wenn Sie also pd.loc verwenden, müssen Sie Ihre logischen Anweisungen in eckige Klammern setzen, andernfalls erhalten Sie eine Fehlermeldung. Deshalb machen Sie:

df.loc[(df['A'] > 10) & (df['B'] < 15)]

anstatt

df.loc[df['A'] > 10 & df['B'] < 15]

was dazu führen würde

TypeError: Ein Array vom Typ dtyped [float64] kann nicht mit einem Skalar vom Typ [bool] verglichen werden.

1