841 Stimmen

Wie man ein Pandas-Dataframe unter Verwendung von 'in' und 'not in' filtert, wie in SQL

Wie kann ich das Äquivalent von SQL's IN und NOT IN erreichen?

Ich habe eine Liste mit den erforderlichen Werten. Hier ist das Szenario:

df = pd.DataFrame({'country': ['US', 'UK', 'Germany', 'China']})
countries_to_keep = ['UK', 'China']

# Pseudo-Code:
df[df['country'] not in countries_to_keep]

Meine aktuelle Methode, dies zu tun, lautet wie folgt:

df = pd.DataFrame({'country': ['US', 'UK', 'Germany', 'China']})
df2 = pd.DataFrame({'country': ['UK', 'China'], 'matched': True})

# IN
df.merge(df2, how='inner', on='country')

# NOT IN
not_in = df.merge(df2, how='left', on='country')
not_in = not_in[pd.isnull(not_in['matched'])]

Aber das scheint wie eine schreckliche Flickschusterei. Kann das jemand verbessern?

1461voto

DSM Punkte 317386

Sie können pd.Series.isin verwenden.

Für "IN" verwenden Sie: something.isin(somewhere)

Oder für "NOT IN": ~something.isin(somewhere)

Als Arbeitsbeispiel:

>>> df
    country
0        US
1        UK
2   Germany
3     China
>>> countries_to_keep
['UK', 'China']
>>> df.country.isin(countries_to_keep)
0    False
1     True
2    False
3     True
Name: country, dtype: bool
>>> df[df.country.isin(countries_to_keep)]
    country
1        UK
3     China
>>> df[~df.country.isin(countries_to_keep)]
    country
0        US
2   Germany

159voto

Alternative Lösung, die die .query() Methode verwendet:

In [5]: df.query("country in @countries_to_keep")
Out[5]:
  countries
1        UK
3     China

In [6]: df.query("country not in @countries_to_keep")
Out[6]:
  countries
0        US
2   Germany

93voto

cs95 Punkte 325143

Wie implementiert man 'in' und 'not in' für ein Pandas DataFrame?

Pandas bietet zwei Methoden: Series.isin und DataFrame.isin für Series und DataFrames.


Filtern des DataFrames basierend auf EINER Spalte (gilt auch für Series)

Das häufigste Szenario ist die Anwendung einer isin-Bedingung auf eine bestimmte Spalte, um Zeilen in einem DataFrame zu filtern.

df = pd.DataFrame({'countries': ['US', 'UK', 'Germany', np.nan, 'China']})
df
  countries
0        US
1        UK
2   Germany
3     China

c1 = ['UK', 'China']             # list
c2 = {'Germany'}                 # set
c3 = pd.Series(['China', 'US'])  # Series
c4 = np.array(['US', 'UK'])      # array

Series.isin akzeptiert verschiedene Eingabetypen. Die folgenden sind alle gültige Arten, um das zu bekommen, was Sie wollen:

df['countries'].isin(c1)

0    False
1     True
2    False
3    False
4     True
Name: countries, dtype: bool

# `in` operation
df[df['countries'].isin(c1)]

  countries
1        UK
4     China

# `not in` operation
df[~df['countries'].isin(c1)]

  countries
0        US
2   Germany
3       NaN

# Filtern mit `set` (Tupel funktionieren ebenfalls)
df[df['countries'].isin(c2)]

  countries
2   Germany

# Filtern mit einer weiteren Series
df[df['countries'].isin(c3)]

  countries
0        US
4     China

# Filtern mit einem Array
df[df['countries'].isin(c4)]

  countries
0        US
1        UK

Filtern auf VIELEN Spalten

Manchmal möchten Sie eine 'in'-Mitgliedschaftsprüfung mit einigen Suchbegriffen über mehrere Spalten anwenden,

df2 = pd.DataFrame({
    'A': ['x', 'y', 'z', 'q'], 'B': ['w', 'a', 'NaN', 'x'], 'C': np.arange(4)})
df2

   A    B  C
0  x    w  0
1  y    a  1
2  z  NaN  2
3  q    x  3

c1 = ['x', 'w', 'p']

Um die isin-Bedingung auf die Spalten "A" und "B" anzuwenden, verwenden Sie DataFrame.isin:

df2[['A', 'B']].isin(c1)

      A      B
0   True   True
1  False  False
2  False  False
3  False   True

Basierend darauf, um Zeilen zu behalten, in denen mindestens eine Spalte True ist, können wir any entlang der ersten Achse verwenden:

df2[['A', 'B']].isin(c1).any(axis=1)

0     True
1    False
2    False
3     True
dtype: bool

df2[df2[['A', 'B']].isin(c1).any(axis=1)]

   A  B  C
0  x  w  0
3  q  x  3

Beachten Sie, dass wenn Sie in jeder Spalte suchen wollen, Sie einfach den Schritt zur Spaltenauswahl weglassen und machen Sie einfach

df2.isin(c1).any(axis=1)

Ebenso, um Zeilen zu behalten, in denen ALLE Spalten True sind, verwenden Sie all auf die gleiche Weise wie zuvor.

df2[df2[['A', 'B']].isin(c1).all(axis=1)]

   A  B  C
0  x  w  0

Erwähnenswert: numpy.isin, query, List Comprehensions (String-Daten)

Zusätzlich zu den oben beschriebenen Methoden können Sie auch das numpy-Äquivalent verwenden: numpy.isin.

# `in` operation
df[np.isin(df['countries'], c1)]

  countries
1        UK
4     China

# `not in` operation
df[np.isin(df['countries'], c1, invert=True)]

  countries
0        US
2   Germany
3       NaN

Warum lohnt es sich, darüber nachzudenken? NumPy-Funktionen sind in der Regel etwas schneller als ihre Pandas-Äquivalente aufgrund eines geringeren Overheads. Da dies eine elementweise Operation ist, die nicht von der Indexausrichtung abhängt, gibt es sehr wenige Situationen, in denen diese Methode kein geeigneter Ersatz für das Pandas-isin ist.

Pandas-Routinen sind in der Regel iterativ, wenn es um Strings geht, da Zeichenfolgenoperationen schwer zu vektorisieren sind. Es gibt viele Hinweise darauf, dass List Comprehensions hier schneller sein werden.. Wir greifen jetzt auf ein in-Check zurück.

c1_set = set(c1) # Die Verwendung von `in` mit `Sets` ist eine Konstantzeitoperation... 
                 # Das spielt für Pandas keine Rolle, da die Implementierung unterschiedlich ist.
# `in` operation
df[[x in c1_set for x in df['countries']]]

  countries
1        UK
4     China

# `not in` operation
df[[x not in c1_set for x in df['countries']]]

  countries
0        US
2   Germany
3       NaN

Es ist viel unhandlicher zu spezifizieren, also verwenden Sie es nicht, es sei denn, Sie wissen, was Sie tun.

Zuletzt gibt es auch DataFrame.query, das in dieser Antwort behandelt wurde. Numexpr FTW!

19voto

Kos Punkte 67505

Normalerweise filtere ich Zeilen allgemein wie folgt:

Kriterium = lambda Zeile: Zeile['Länder'] not in Länder
nicht_in = df[df.apply(Kriterium, axis=1)]

17voto

Abhishek Gaur Punkte 607

Zusammenfassung möglicher Lösungen aus den Antworten:

Für IN: df[df['A'].isin([3, 6])]

Für NOT IN:

  1. df[-df["A"].isin([3, 6])]

  2. df[~df["A"].isin([3, 6])]

  3. df[df["A"].isin([3, 6]) == False]

  4. df[np.logical_not(df["A"].isin([3, 6]))]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X