Hoe kan ik de equivalenten van SQL’s bereiken in
en 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.isin
en DataFrame.isin
voor 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.isin
accepteert 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']
isin
staat 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 any
langs 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 True
gebruik all
op 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 in
controle.
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.query
dat 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:
-
df[-df["A"].isin([3, 6])]
-
df[~df["A"].isin([3, 6])]
-
df[df["A"].isin([3, 6]) == False]
-
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"
),
)