python - example - pandas where
pandas: la mejor manera de seleccionar todas las columnas cuyos nombres comienzan con X (6)
Ahora que los índices de los pandas admiten operaciones de cadena, podría decirse que la forma más simple y mejor de seleccionar columnas que comienzan con ''foo'' es simplemente:
df.loc[:, df.columns.str.startswith(''foo'')]
Alternativamente, puede filtrar las etiquetas de columna (o fila) con
df.filter()
.
Para especificar una expresión regular que coincida con los nombres que comienzan con
foo.
:
>>> df.filter(regex=r''^foo/.'', axis=1)
foo.aa foo.bars foo.fighters foo.fox foo.manchu
0 1.0 0 0 2 NA
1 2.1 0 1 4 0
2 NaN 0 NaN 1 0
3 4.7 0 0 0 0
4 5.6 0 0 0 0
5 6.8 1 0 5 0
Para seleccionar solo las filas requeridas (que contienen un
1
) y las columnas, puede usar
loc
, seleccionando las columnas con
filter
(o cualquier otro método) y las filas con
any
:
>>> df.loc[(df == 1).any(axis=1), df.filter(regex=r''^foo/.'', axis=1).columns]
foo.aa foo.bars foo.fighters foo.fox foo.manchu
0 1.0 0 0 2 NA
1 2.1 0 1 4 0
2 NaN 0 NaN 1 0
5 6.8 1 0 5 0
Tengo un DataFrame:
import pandas as pd
import numpy as np
df = pd.DataFrame({''foo.aa'': [1, 2.1, np.nan, 4.7, 5.6, 6.8],
''foo.fighters'': [0, 1, np.nan, 0, 0, 0],
''foo.bars'': [0, 0, 0, 0, 0, 1],
''bar.baz'': [5, 5, 6, 5, 5.6, 6.8],
''foo.fox'': [2, 4, 1, 0, 0, 5],
''nas.foo'': [''NA'', 0, 1, 0, 0, 0],
''foo.manchu'': [''NA'', 0, 0, 0, 0, 0],})
Quiero seleccionar valores de 1 en columnas que comienzan con
foo.
.
¿Hay una mejor manera de hacerlo que no sea:
df2 = df[(df[''foo.aa''] == 1)|
(df[''foo.fighters''] == 1)|
(df[''foo.bars''] == 1)|
(df[''foo.fox''] == 1)|
(df[''foo.manchu''] == 1)
]
Algo similar a escribir algo como:
df2= df[df.STARTS_WITH_FOO == 1]
La respuesta debería imprimir un DataFrame como este:
bar.baz foo.aa foo.bars foo.fighters foo.fox foo.manchu nas.foo
0 5.0 1.0 0 0 2 NA NA
1 5.0 2.1 0 1 4 0 0
2 6.0 NaN 0 NaN 1 0 1
5 6.8 6.8 1 0 5 0 0
[4 rows x 7 columns]
La forma más simple es usar str directamente en los nombres de columna, no hay necesidad de
pd.Series
df.loc[:,df.columns.str.startswith("foo")]
Mi solución. Puede ser más lento en rendimiento:
a = pd.concat(df[df[c] == 1] for c in df.columns if c.startswith(''foo''))
a.sort_index()
bar.baz foo.aa foo.bars foo.fighters foo.fox foo.manchu nas.foo
0 5.0 1.0 0 0 2 NA NA
1 5.0 2.1 0 1 4 0 0
2 6.0 NaN 0 NaN 1 0 1
5 6.8 6.8 1 0 5 0 0
Otra opción para la selección de las entradas deseadas es utilizar el
map
:
df.loc[(df == 1).any(axis=1), df.columns.map(lambda x: x.startswith(''foo''))]
que le da todas las columnas para las filas que contienen un
1
:
foo.aa foo.bars foo.fighters foo.fox foo.manchu
0 1.0 0 0 2 NA
1 2.1 0 1 4 0
2 NaN 0 NaN 1 0
5 6.8 1 0 5 0
La selección de fila se realiza por
(df == 1).any(axis=1)
como en la respuesta de @ ajcr que te da:
0 True
1 True
2 True
3 False
4 False
5 True
dtype: bool
lo que significa que las filas
3
y
4
no contienen un
1
y no se seleccionarán.
La selección de las columnas se realiza mediante una indexación booleana como esta:
df.columns.map(lambda x: x.startswith(''foo''))
En el ejemplo anterior, esto devuelve
array([False, True, True, True, True, True, False], dtype=bool)
Entonces, si una columna no comienza con
foo
, se devuelve
False
y, por lo tanto, la columna no se selecciona.
Si solo desea devolver todas las filas que contienen un
1
, como sugiere la salida deseada, simplemente puede hacer
df.loc[(df == 1).any(axis=1)]
que vuelve
bar.baz foo.aa foo.bars foo.fighters foo.fox foo.manchu nas.foo
0 5.0 1.0 0 0 2 NA NA
1 5.0 2.1 0 1 4 0 0
2 6.0 NaN 0 NaN 1 0 1
5 6.8 6.8 1 0 5 0 0
Según la respuesta de @ EdChum, puede probar la siguiente solución:
df[df.columns[pd.Series(df.columns).str.contains("foo")]]
Esto será realmente útil en caso de que no todas las columnas que desea seleccionar comiencen con
foo
.
Este método selecciona todas las columnas que contienen la subcadena
foo
y se puede colocar en cualquier punto del nombre de una columna.
En esencia, reemplacé
.startswith()
con
.contains()
.
Simplemente realice una comprensión de la lista para crear sus columnas:
In [28]:
filter_col = [col for col in df if col.startswith(''foo'')]
filter_col
Out[28]:
[''foo.aa'', ''foo.bars'', ''foo.fighters'', ''foo.fox'', ''foo.manchu'']
In [29]:
df[filter_col]
Out[29]:
foo.aa foo.bars foo.fighters foo.fox foo.manchu
0 1.0 0 0 2 NA
1 2.1 0 1 4 0
2 NaN 0 NaN 1 0
3 4.7 0 0 0 0
4 5.6 0 0 0 0
5 6.8 1 0 5 0
Otro método es crear una serie a partir de las columnas y utilizar el método str
startswith
:
In [33]:
df[df.columns[pd.Series(df.columns).str.startswith(''foo'')]]
Out[33]:
foo.aa foo.bars foo.fighters foo.fox foo.manchu
0 1.0 0 0 2 NA
1 2.1 0 1 4 0
2 NaN 0 NaN 1 0
3 4.7 0 0 0 0
4 5.6 0 0 0 0
5 6.8 1 0 5 0
Para lograr lo que desea, debe agregar lo siguiente para filtrar los valores que no cumplan con sus criterios
==1
:
In [36]:
df[df[df.columns[pd.Series(df.columns).str.startswith(''foo'')]]==1]
Out[36]:
bar.baz foo.aa foo.bars foo.fighters foo.fox foo.manchu nas.foo
0 NaN 1 NaN NaN NaN NaN NaN
1 NaN NaN NaN 1 NaN NaN NaN
2 NaN NaN NaN NaN 1 NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN 1 NaN NaN NaN NaN
EDITAR
OK después de ver lo que quieres, la respuesta complicada es esta:
In [72]:
df.loc[df[df[df.columns[pd.Series(df.columns).str.startswith(''foo'')]] == 1].dropna(how=''all'', axis=0).index]
Out[72]:
bar.baz foo.aa foo.bars foo.fighters foo.fox foo.manchu nas.foo
0 5.0 1.0 0 0 2 NA NA
1 5.0 2.1 0 1 4 0 0
2 6.0 NaN 0 NaN 1 0 1
5 6.8 6.8 1 0 5 0 0