Hoe Pandas-dataframe filteren met ‘in’ en ‘niet in’ zoals in SQL

Hoe kan ik de equivalenten van SQL’s bereiken inen NOT IN?

Ik heb een lijst met de vereiste waarden.
Hier is het scenario:

df = pd.DataFrame({'country': ['US', 'UK', 'Germany', 'China']})
countries_to_keep = ['UK', 'China']
# pseudo-code:
df[df['country'] not in countries_to_keep]

Mijn huidige manier van doen is als volgt:

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'])]

Maar dit lijkt een vreselijke klier. Kan iemand het verbeteren?


Antwoord 1, Autoriteit 100%

U kunt pd.Series.isin.

Gebruik voor “in”: something.isin(somewhere)

of voor “niet in”: ~something.isin(somewhere)

Als uitgewerkte voorbeeld:

import pandas as pd
>>> 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

Antwoord 2, autoriteit 9%

Alternatieve oplossing die gebruikmaakt van .query() methode:

In [5]: df.query("countries in @countries")
Out[5]:
  countries
1        UK
3     China
In [6]: df.query("countries not in @countries")
Out[6]:
  countries
0        US
2   Germany

Antwoord 3, autoriteit 6%

Hoe implementeer je ‘in’ en ‘not in’ voor een panda’s DataFrame?

Pandas biedt twee methoden: Series.isinen DataFrame.isinvoor respectievelijk Series en DataFrames.


Filter DataFrame Gebaseerd op EEN Kolom (geldt ook voor Serie)

Het meest voorkomende scenario is het toepassen van een isin-voorwaarde op een specifieke kolom om rijen in een DataFrame te filteren.

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.isinaccepteert verschillende typen als invoer. De volgende zijn allemaal geldige manieren om te krijgen wat je wilt:

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

# Filter with `set` (tuples work too)
df[df['countries'].isin(c2)]
  countries
2   Germany

# Filter with another Series
df[df['countries'].isin(c3)]
  countries
0        US
4     China

# Filter with array
df[df['countries'].isin(c4)]
  countries
0        US
1        UK

Filter op veel kolommen

Soms wil je een toe te passen ‘in’ lidmaatschap check met een aantal zoektermen over meerdere kolommen,

df2 = pd.DataFrame({
    'A': ['x', 'y', 'z', 'q'], 'B': ['w', 'a', np.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']

isinstaat voor beide kolommen “A” en “B”, gebruik DataFrame.isin:

df2[['A', 'B']].isin(c1)
      A      B
0   True   True
1  False  False
2  False  False
3  False   True

Hieruit rijen te houden indien ten minste één kolom True, kunnen we anylangs de eerste as:

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

Merk op dat als je wilt elke kolom te zoeken, zou je gewoon weglaten de selectie kolomstapinterval en doen

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

Op dezelfde rijen te houden indien alle kolommen Truegebruik allop dezelfde wijze als hiervoor.

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

Notable vermeldingen: numpy.isin, query, Lijstcomprehensies (string data)

Naast de werkwijzen die hierboven zijn beschreven, kunt u ook numpy equivalent daarvan gebruikt: 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

Waarom is het het overwegen waard? NumPy functies zijn meestal een beetje sneller dan hun panda equivalenten als gevolg van lagere overhead. Omdat dit een elementsgewijze handeling die niet afhankelijk index aanpassing, zijn er zeer weinig situaties waarin deze werkwijze geen geschikte vervanger voor panda isin.

Pandas routines zijn meestal iteratief bij het werken met strijkers, want string operaties zijn moeilijk te vectorize. Er is veel bewijs om te suggereren dat Lijstcomprehensies sneller hier zal zijn. .
We nemen nu onze toevlucht tot een incontrole.

c1_set = set(c1) # Using `in` with `sets` is a constant time operation... 
                 # This doesn't matter for pandas because the implementation differs.
# `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

Het is echter een stuk lastiger om te specificeren, dus gebruik het niet tenzij u weet wat u doet.

Ten slotte is er ook DataFrame.querydat is behandeld in dit antwoord. numexpr FTW!


Antwoord 4

Ik heb gewoonlijk generieke filters over rijen als volgt gedaan:

criterion = lambda row: row['countries'] not in countries
not_in = df[df.apply(criterion, axis=1)]

Antwoord 5

Verzamelen van mogelijke oplossingen uit de antwoorden:

Voor IN: df[df['A'].isin([3, 6])]

Voor NIET 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]))]


Antwoord 6

Ik wilde dfbc-rijen uitfilteren die een BUSINESS_ID hadden die ook in de BUSINESS_ID van dfProfilesBusIds stond

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

Antwoord 7

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

implementeren in :

df[df.countries.isin(countries)]

Implementeer niet in Net als in uitgelegen landen:

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

Antwoord 8

een truc als u de volgorde van de lijst wilt behouden:

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

Antwoord 9

My 2C Worth:
Ik had een combinatie van in en Ifelse-verklaringen voor een dataframe nodig, en dit werkte voor mij.

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"
    ),
)

Other episodes