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?

0voto

GenDemo Punkte 671

Meine Meinung: Ich brauchte eine Kombination von in- und ifelse-Anweisungen für ein DataFrame, und das hat für mich funktioniert.

sale_method = pd.DataFrame(model_data["Sale Method"].str.upper())
sale_method["sale_classification"] = np.where(
    sale_method["Sale Method"].isin(["PRIVATE"]),
    "private",
    np.where(
        sale_method["Sale Method"].str.contains("AUCTION"), "auction", "other"
    ),
)

0voto

not a robot Punkte 3525

groupby könnte verwendet werden, um ein DataFrame in zwei aufzuteilen

Wenn das Ziel darin besteht, ein DataFrame in zwei DataFrames aufzuteilen, wobei eines die Länder zum Behalten enthält und das andere nicht, kann die durch den isin-Aufruf erstellte boolesche Maske in einem groupby-Aufruf verwendet werden, um das DataFrame in zwei aufzuteilen: haben und nicht haben.

df = pd.DataFrame({'country': ['US', 'UK', 'Germany', 'China'], 'value': range(4)})
countries_to_keep = ['UK', 'China']
df1, df2 = [g for _, g in df.groupby(df['country'].isin(countries_to_keep))]

Ergebnis

eval() könnte auch verwendet werden

query() wird an anderer Stelle vorgeschlagen, um einen numerischen Ausdruck auszuwerten. Eine verwandte Methode ist eval(). Es kann verwendet werden, um eine boolesche Maske zu erstellen und ein DataFrame zu filtern. Es kann mit anderen Masken verwendet werden, die vielleicht anderswo erstellt wurden, um ein flexibleres Filtern zu ermöglichen.

msk = df.eval('country in @countries_to_keep')
to_keep = df[msk]     # in
not_keep = df[~msk]   # not in

Ein besonderer Fall, in dem dies nützlich ist, besteht darin, wenn Sie eine einzelne Spalte unter Verwendung einer Bedingung filtern möchten. query ist sehr speicherineffizient, da es eine Kopie des gefilterten Frames erstellt, der erneut für eine einzelne Spalte gefiltert werden muss, während loc die Spalte in einem Schritt unter Verwendung einer booleschen Maske-Spaltenbezeichnungskombination auswählt. eval() kann dasselbe tun.1

df = pd.DataFrame({'country': ['US', 'UK', 'Germany', 'China']*25000})
df[[f"col{i}" for i in range(50)]] = np.random.rand(100000, 50)
countries_to_keep = ['UK', 'China']

filtered = df.loc[df.eval('country==@countries_to_keep'), 'col1']

1 Ein Speicherprofilertest:

import numpy as np
import pandas as pd
%load_ext memory_profiler

df = pd.DataFrame({'country': ['US', 'UK', 'Germany', 'China']*25000})
df[[f"col{i}" for i in range(50)]] = np.random.rand(100000, 50)
countries_to_keep = ['UK', 'China']

%memit x = df.loc[df.eval('country==@countries_to_keep'), 'col1']
# peak memory: 157.28 MiB, increment: 5.44 MiB

%memit y = df.query('country==@countries_to_keep')['col1']
# peak memory: 195.39 MiB, increment: 38.11 MiB

%memit z = df.loc[df['country'].isin(countries_to_keep), 'col1']
# peak memory: 176.93 MiB, increment: 0.76 MiB

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