Cómo implementar ‘in’ y ‘not in’ para el dataframe de Pandas

¿Cómo puedo lograr los equivalentes de SQL 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 embrollo. ¿Alguien puede mejorarlo?

Puedes usar pd.Series.isin .

Para “IN”: somewhere.isin(something) (lea: ¿hay something ahí en somewhere ?)

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

Como ejemplo:

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

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 

Por lo general, he estado filtrando genéricamente filas como esta:

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

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

Finalmente lo puse en funcionamiento:

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

¿Cómo implementar y not in un dataframe de pandas?

Pandas ofrece dos métodos: Series.isin y DataFrame.isin para Series y DataFrames, respectivamente. Aquí está el mapeo de los operadores de python titulares a sus operaciones de pandas equivalentes.

 ╒════════╤══════════════════════╤══════════════════════╕ │ │ Python │ Pandas │ ╞════════╪══════════════════════╪══════════════════════╡ │ in │ item in sequence │ sequence.isin(item) │ ├────────┼──────────────────────┼──────────────────────┤ │ not in │ item not in sequence │ ~sequence.isin(item) │ ╘════════╧══════════════════════╧══════════════════════╛ 

Para implementar “no en”, debe invertir el resultado de isin .

También tenga en cuenta que, en el caso de los pandas, la ” sequence ” puede referirse a una Serie o Marco de Datos, y el ” item ” puede ser un iterable (más sobre esto pronto).


Filtrar dataframe basado en UNA columna (también se aplica a la serie)

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

Filtrar en muchas columnas

A veces, deseará aplicar una verificación de membresía “en” 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 ABC 0 xw 0 1 ya 1 2 z NaN 2 3 qx 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) AB 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)] ABC 0 xw 0 3 qx 3 

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

 df2[df2[['A', 'B']].isin(c1).all(axis=1)] ABC 0 xw 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 de NumPy suelen ser un poco más rápidas que sus equivalentes de pandas debido a una menor sobrecarga. Debido a que esta es una operación elemental que no depende de la alineación del índice, hay muy pocas situaciones en las que este método no es un reemplazo apropiado para el isin de pandas.

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 listas de comprensión serán más rápidas aquí. . Recurrimos a un 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!

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

implementar en :

 df[df.countries.isin(countries)] 

Implementar no en como en países de descanso:

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