Панды: лучший способ выбрать все столбцы, имена которых начинаются с X
У меня есть 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],})
Я хочу выбрать значения 1 в столбцах, начиная с foo.
. Есть ли лучший способ сделать это, кроме:
df2 = df[(df['foo.aa'] == 1)|
(df['foo.fighters'] == 1)|
(df['foo.bars'] == 1)|
(df['foo.fox'] == 1)|
(df['foo.manchu'] == 1)
]
Нечто похожее на что-то вроде:
df2= df[df.STARTS_WITH_FOO == 1]
Ответ должен распечатать DataFrame следующим образом:
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]
Ответы
Ответ 1
Просто создайте список для создания столбцов:
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
Другой метод - создать серию из столбцов и использовать метод vectorized 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
Чтобы добиться желаемого результата, вам необходимо добавить следующие значения для фильтрации значений, которые не соответствуют вашим критериям ==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
ИЗМЕНИТЬ
ОК, посмотрев, что вы хотите, это запутанный ответ:
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
Ответ 2
Теперь, когда индексы pandas поддерживают строковые операции, возможно, самый простой и лучший способ выбрать столбцы, начинающиеся с 'foo', это просто:
df.loc[:, df.columns.str.startswith('foo')]
Кроме того, вы можете фильтровать метки столбцов (или строк) с помощью df.filter()
. Чтобы указать регулярное выражение для соответствия именам, начинающимся с 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
Чтобы выбрать только необходимые строки (содержащие 1
) и столбцы, вы можете использовать loc
, выбирая столбцы с помощью filter
(или любым другим методом) и строки с помощью 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
Ответ 3
Мое решение. Это может быть медленнее при работе:
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
Ответ 4
Другим вариантом выбора нужных записей является использование map
:
df.loc[(df == 1).any(axis=1), df.columns.map(lambda x: x.startswith('foo'))]
который дает вам все столбцы для строк, которые содержат 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
выбор строки выполняется
(df == 1).any(axis=1)
как в ответе @ajcr, который дает вам:
0 True
1 True
2 True
3 False
4 False
5 True
dtype: bool
означает, что строки 3
и 4
не содержат 1
и не будут выбраны.
выбор столбцов выполняется с помощью булевого индексирования следующим образом:
df.columns.map(lambda x: x.startswith('foo'))
В приведенном выше примере возвращается
array([False, True, True, True, True, True, False], dtype=bool)
Итак, если столбец не начинается с foo
, возвращается False
, и поэтому столбец не выбран.
Если вы просто хотите вернуть все строки, содержащие 1
, как вам кажется, вы можете сделать
df.loc[(df == 1).any(axis=1)]
который возвращает
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
Ответ 5
Основываясь на ответе @EdChum, вы можете попробовать следующее решение:
df[df.columns[pd.Series(df.columns).str.contains("foo")]]
Это будет действительно полезно, если не все столбцы, которые вы хотите выбрать, начинаются с foo
. Этот метод выбирает все столбцы, которые содержат подстроку foo
, и ее можно разместить в любой точке имени столбца.
По сути, я заменил .startswith()
на .contains()
.