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?

12voto

Sam Henderson Punkte 469

Ich wollte die dfbc-Zeilen filtern, die eine BUSINESS_ID hatten, die auch in der BUSINESS_ID von dfProfilesBusIds enthalten war

dfbc = dfbc[~dfbc['BUSINESS_ID'].isin(dfProfilesBusIds['BUSINESS_ID'])]

12voto

padu Punkte 294

Warum spricht niemand über die Leistung verschiedener Filtermethoden? Tatsächlich taucht dieses Thema hier oft auf (siehe Beispiel). Ich habe meinen eigenen Leistungstest für einen großen Datensatz gemacht. Es ist sehr interessant und lehrreich.

df = pd.DataFrame({'animals': np.random.choice(['cat', 'dog', 'mouse', 'birds'], size=10**7), 
                   'number': np.random.randint(0,100, size=(10**7,))})

df.info()

RangeIndex: 10000000 entries, 0 to 9999999
Data columns (total 2 columns):
 #   Column   Dtype 
---  ------   ----- 
 0   animals  object
 1   number   int64 
dtypes: int64(1), object(1)
memory usage: 152.6+ MB

%%timeit
# .isin() nach einer Spalte
conditions = ['cat', 'dog']
df[df.animals.isin(conditions)]

367 ms ± 2.34 ms pro Schleife (mean ± std. dev. von 7 Schleifen, 1 Schleife pro Durchlauf)

%%timeit
# .query() nach einer Spalte
conditions = ['cat', 'dog']
df.query('animals in @conditions')

395 ms ± 3.9 ms pro Schleife (mean ± std. dev. von 7 Schleifen, 1 Schleife pro Durchlauf)

%%timeit
# .loc[]
df.loc[(df.animals=='cat')|(df.animals=='dog')]

987 ms ± 5.17 ms pro Schleife (mean ± std. dev. von 7 Schleifen, 1 Schleife pro Durchlauf)

%%timeit
df[df.apply(lambda x: x['animals'] in ['cat', 'dog'], axis=1)]

41.9 s ± 490 ms pro Schleife (mean ± std. dev. von 7 Schleifen, 1 Schleife pro Durchlauf)

%%timeit
new_df = df.set_index('animals')
new_df.loc[['cat', 'dog'], :]

3.64 s ± 62.5 ms pro Schleife (mean ± std. dev. von 7 Schleifen, 1 Schleife pro Durchlauf)

%%timeit
new_df = df.set_index('animals')
new_df[new_df.index.isin(['cat', 'dog'])]

469 ms ± 8.98 ms pro Schleife (mean ± std. dev. von 7 Schleifen, 1 Schleife pro Durchlauf)

%%timeit
s = pd.Series(['cat', 'dog'], name='animals')
df.merge(s, on='animals', how='inner')

796 ms ± 30.9 ms pro Schleife (mean ± std. dev. von 7 Schleifen, 1 Schleife pro Durchlauf)

Somit stellte sich heraus, dass die Methode isin die schnellste und die Methode mit apply() die langsamste war, was nicht überraschend ist.

7voto

rachwa Punkte 181

Sie können auch .isin() innerhalb von .query() verwenden:

df.query('country.isin(@countries_to_keep).values')

# Oder alternativ:
df.query('country.isin(["UK", "China"]).values')

Um Ihre Abfrage zu negieren, verwenden Sie ~:

df.query('~country.isin(@countries_to_keep).values')

Aktualisierung:

Ein weiterer Weg ist die Verwendung von Vergleichsoperatoren:

df.query('country == @countries_to_keep')

# Oder alternativ:
df.query('country == ["UK", "China"]')

Und um die Abfrage zu negieren, verwenden Sie !=:

df.query('country != @countries_to_keep')

5voto

Ioannis Nasios Punkte 7913
df = pd.DataFrame({'countries':['US','UK','Germany','China']})
länder = ['UK','China']

implementieren in:

df[df.countries.isin(länder)]

implementieren nicht in wie bei den restlichen Ländern:

df[df.countries.isin([x for x in np.unique(df.countries) if x not in länder])]

3voto

Billy Bonaros Punkte 1521

Ein Trick, wenn Sie die Reihenfolge der Liste beibehalten möchten:

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

ind=[df.index[df['country']==i].tolist() for i in countries_to_keep]
flat_ind=[item for sublist in ind for item in sublist]

df.reindex(flat_ind)

   country
2  Germany
0       US

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