Comment puis-je obtenir les équivalents de IN
et NOT IN
de SQL?
J'ai une liste avec les valeurs requises. Voici le scénario:
df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = ['UK','China']
# pseudo-code:
df[df['countries'] not in countries]
Ma façon actuelle de le faire est la suivante:
df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = pd.DataFrame({'countries':['UK','China'], 'matched':True})
# IN
df.merge(countries,how='inner',on='countries')
# NOT IN
not_in = df.merge(countries,how='left',on='countries')
not_in = not_in[pd.isnull(not_in['matched'])]
Mais cela ressemble à un horrible kludge. Quelqu'un peut-il l'améliorer?
Vous pouvez utiliser pd.Series.isin
.
Pour "IN", utilisez: something.isin(somewhere)
Ou pour "NOT IN": ~something.isin(somewhere)
A titre d'exemple travaillé:
_>>> df
countries
0 US
1 UK
2 Germany
3 China
>>> countries
['UK', 'China']
>>> df.countries.isin(countries)
0 False
1 True
2 False
3 True
Name: countries, dtype: bool
>>> df[df.countries.isin(countries)]
countries
1 UK
3 China
>>> df[~df.countries.isin(countries)]
countries
0 US
2 Germany
_
Solution alternative utilisant la méthode . Query () :
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
Comment implémenter 'in' et 'not in' pour un pandas DataFrame?
Pandas propose deux méthodes: Series.isin
et DataFrame.isin
pour Series et DataFrames, respectivement.
Le scénario le plus courant consiste à appliquer une condition isin
sur une colonne spécifique pour filtrer les lignes d'un DataFrame.
_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
_ accepte différents types en tant qu'entrées. Voici tous les moyens valables d’obtenir ce que vous voulez:
_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
_
Parfois, vous voudrez appliquer une vérification de membre "in" avec certains termes de recherche sur plusieurs colonnes,
_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']
_
Pour appliquer la condition isin
aux deux colonnes "A" et "B", utilisez _DataFrame.isin
_:
_df2[['A', 'B']].isin(c1)
A B
0 True True
1 False False
2 False False
3 False True
_
À partir de cela, pour conserver les lignes dont au moins une colonne est True
, on peut utiliser any
le long du premier axe:
_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
_
Notez que si vous souhaitez effectuer une recherche dans chaque colonne, il vous suffit d’omettre l’étape de sélection
_df2.isin(c1).any(axis=1)
_
De même, pour conserver les lignes où TOUTES les colonnes sont True
, utilisez all
de la même manière qu'auparavant.
_df2[df2[['A', 'B']].isin(c1).all(axis=1)]
A B C
0 x w 0
_
numpy.isin
_, query
, compréhensions de liste (données de chaîne)En plus des méthodes décrites ci-dessus, vous pouvez également utiliser l'équivalent numpy: 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
_
Pourquoi cela vaut-il la peine d'être envisagé? Les fonctions NumPy sont généralement un peu plus rapides que leurs équivalents pandas en raison de la réduction des frais généraux. Comme il s’agit d’une opération élémentaire ne dépendant pas de l’alignement d’index, il existe très peu de situations dans lesquelles cette méthode n’est pas un remplacement approprié pour les pandas 'isin
.
Les routines de pandas sont généralement itératives lorsque vous travaillez avec des chaînes, car les opérations sur les chaînes sont difficiles à vectoriser. De nombreuses preuves suggèrent que la compréhension des listes sera plus rapide ici. . Nous avons recours à une vérification in
maintenant.
_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
_
Il est toutefois beaucoup plus difficile à préciser, alors ne l'utilisez pas à moins de savoir ce que vous faites.
Enfin, il y a aussi _DataFrame.query
_ qui a été couvert dans cette réponse . numexpr FTW!
Je fais habituellement du filtrage générique sur des lignes comme ceci:
criterion = lambda row: row['countries'] not in countries
not_in = df[df.apply(criterion, axis=1)]
Je voulais filtrer les lignes dfbc ayant un BUSINESS_ID qui figurait également dans le BUSINESS_ID de dfProfilesBusIds
dfbc = dfbc[~dfbc['BUSINESS_ID'].isin(dfProfilesBusIds['BUSINESS_ID'])]
df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = ['UK','China']
implémenter dans:
df[df.countries.isin(countries)]
mettre en œuvre pas dans comme dans des pays de repos:
df[df.countries.isin([x for x in np.unique(df.countries) if x not in countries])]
Rassembler les solutions possibles à partir des réponses:
Pour IN: df[df['A'].isin([3, 6])]
Pour NOT 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]))]