Cómo filtrar el marco de datos de Pandas usando "en" y "no en" como en SQL

python pandas dataframe sql-function


¿Cómo puedo lograr los equivalentes de SQL's IN y NOT IN ?

Tengo una lista con los valores requeridos.Aquí está el escenario:

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

# pseudo-code:
df[df['countries'] not in countries]

Mi forma actual de hacer esto es la siguiente:

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

Pero esto parece un horrible golpe.¿Alguien puede mejorarlo?




Answer 1 DSM


Puede usar pd.Series.isin .

Para uso "IN": something.isin(somewhere)

O para "NOT IN": ~something.isin(somewhere)

Como ejemplo práctico:

>>> 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



Answer 2 MaxU


Solución alternativa que utiliza el método .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



Answer 3 cs95


¿Cómo implementar "en" y "no en" para un DataFrame de pandas?

Pandas ofrece dos métodos: Series.isin y DataFrame.isin para Series y DataFrames, respectivamente.


Filtro DataFrame basado en una columna (también se aplica a las series)

El escenario más común es aplicar una condición isin en una columna específica para filtrar filas en 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 acepta varios tipos como entradas. Las siguientes son formas válidas de obtener lo que desea:

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

Filtro en MUCHAS Columnas

A veces,querrá aplicar una verificación de membresía "in" con algunos términos de búsqueda en varias columnas,

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

Para aplicar la condición isin a ambas columnas "A" y "B", use DataFrame.isin :

df2[['A', 'B']].isin(c1)

      A      B
0   True   True
1  False  False
2  False  False
3  False   True

A partir de esto, para retener filas donde al menos una columna es True , podemos usar any largo del primer eje:

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

Ten en cuenta que si quieres buscar en todas las columnas,sólo tienes que omitir el paso de selección de columna y hacer

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

De manera similar, para retener filas donde TODAS las columnas son True , use all de la misma manera que antes.

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

   A  B  C
0  x  w  0

Menciones notables: numpy.isin , query , comprensión de listas (datos de cadena)

Además de los métodos descritos anteriormente, también puede usar el equivalente numpy.isin : 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

¿Por qué vale la pena considerarlo? Las funciones NumPy suelen ser un poco más rápidas que sus equivalentes pandas debido a una menor sobrecarga. Dado que esta es una operación elementwise que no depende de la alineación índice, hay muy pocas situaciones en las que este método no es un sustituto adecuado para pandas isin .

Las rutinas de pandas suelen ser iterativas cuando se trabaja con cadenas, porque las operaciones de cadena son difíciles de vectorizar. Hay mucha evidencia que sugiere que las comprensiones de listas serán más rápidas aquí. . Se recurre a una in cheque ahora.

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

Sin embargo,es mucho más difícil de especificar,así que no lo uses a menos que sepas lo que estás haciendo.

Por último, también hay DataFrame.query que se ha cubierto en esta respuesta . numexpr FTW!




Answer 4 Kos


Normalmente he estado haciendo un filtrado genérico sobre filas como esta:

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



Answer 5 Sam Henderson


Quería filtrar las filas de dfbc que tenían un BUSINESS_ID que también estaba en el BUSINESS_ID de dfProfilesBusIds

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