python - Seleccionar columnas si alguna de sus filas contiene una cadena determinada
pandas dataframe (5)
stack
con
any
df.columns[df.stack().str.contains(''%'').any(level=1)]
Index([''C'', ''D''], dtype=''object'')
comprensión
[c for c in df if df[c].str.contains(''%'').any()]
[''C'', ''D'']
filter
[*filter(lambda c: df[c].str.contains(''%'').any(), df)]
[''C'', ''D'']
Hallazgo de numpy
from numpy.core.defchararray import find
df.columns[(find(df.to_numpy().astype(str), ''%'') >= 0).any(0)]
Index([''C'', ''D''], dtype=''object'')
Estoy intentando obtener una lista de columnas en un DataFrame si algún valor en una columna contiene una cadena. Por ejemplo, en el siguiente marco de datos, me gustaría una lista de columnas que tengan el% en la cadena. Puedo lograr esto usando un método for y el método series.str.contains pero no parece óptimo, especialmente con un conjunto de datos más grande. ¿Hay una manera más eficiente de hacer esto?
import pandas as pd
df = pd.DataFrame({''A'': {0: ''2019-06-01'', 1: ''2019-06-01'', 2: ''2019-06-01''},
''B'': {0: ''10'', 1: ''20'', 2: ''30''},
''C'': {0: ''10'', 1: ''20%'', 2: ''30%''},
''D'': {0: ''10%'', 1: ''20%'', 2: ''30''},
})
Marco de datos
A B C D
0 2019-06-01 10 10 10%
1 2019-06-01 20 20% 20%
2 2019-06-01 30 30% 30
Método actual
col_list = []
for col in df.columns:
if (True in list(df[col].str.contains(''%''))) is True:
col_list.append(col)
Salida
[''C'', ''D'']
Compare con
replace
y cree una máscara para indexar las columnas en consecuencia:
df.loc[:,(df != df.replace(''%'', '''', regex=True)).any()]
C D
0 10 10%
1 20% 20%
2 30% 30
df.columns[(df != df.replace(''%'', '''', regex=True)).any()]
# Index([''C'', ''D''], dtype=''object'')
Esto evita la necesidad de un bucle, una
apply
o un
applymap
.
Primero use
DataFrame.select_dtypes
para filtrar solo columnas de objetos, obviamente cadenas de cadenas.
Luego use
DataFrame.applymap
para los valores de verificación elementales con
DataFrame.any
para devolver True si hay al menos una por columna, por lo que es posible filtrar columnas:
c = df.columns[df.select_dtypes(object).applymap(lambda x: ''%'' in str(x)).any()].tolist()
print (c)
[''C'', ''D'']
O use
Series.str.contains
por columnas, el parámetro
na
debe omitirse si todas las columnas de cadenas:
f = lambda x: x.str.contains(''%'', na=False)
c = df.columns[df.select_dtypes(object).apply(f).any()].tolist()
print (c)
[''C'', ''D'']
Prueba esto:
df.columns[df.apply(lambda x: x.str.contains("/%")).any()]
Vamos a
melt
df.melt().loc[lambda x :x.value.str.contains(''%''),''variable''].unique()
Out[556]: array([''C'', ''D''], dtype=object)