如何在熊猫 DataFrame 中选择名称以 X 开头的所有列

我有一个数据框架:

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],})

我想在从 foo.开始的列中选择值1。除了:

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]
193849 次浏览

只要执行一个列表内涵来创建你的专栏:

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

另一种方法是从列中创建一个序列,并使用向量化的 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

既然大熊猫的索引支持字符串运算,可以说选择以“ 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

我的解决方案。它可能在性能上更慢:

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

选择所需条目的另一个选项是使用 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

意味着行 34不包含 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

根据@EdChum 的回答,您可以尝试以下解决方案:

df[df.columns[pd.Series(df.columns).str.contains("foo")]]

如果不是所有要选择的列都以 foo开始,这将非常有帮助。此方法选择包含子字符串 foo的所有列,并且可以将其放置在列名的任何位置。

实际上,我用 .contains()代替了 .startswith()

最简单的方法是直接对列名使用 str,不需要 pd.Series

df.loc[:,df.columns.str.startswith("foo")]




您可以在这里尝试正则表达式来过滤以“ foo”开头的列

df.filter(regex='^foo*')

如果您需要在您的专栏中使用字符串 foo,那么

df.filter(regex='foo*')

是合适的。

对于下一步,您可以使用

df[df.filter(regex='^foo*').values==1]

筛选出‘ foo *’列中的一个值为1的行。

在我的情况下,我需要一个前缀列表

colsToScale=["production", "test", "development"]
dc[dc.columns[dc.columns.str.startswith(tuple(colsToScale))]]

我不喜欢其他解决方案要求我们两次引用 DataFrame; 如果您只有一个名为 df的帧,这可能没问题,但通常情况并非如此(您的实际名称可能更长)。让我们利用熊猫索引功能少输入,使代码更具可读性。没有什么能阻止我们使用这样的东西:

df.loc[:, columns.startswith('foo')]

因为索引器可以是任意 Callable。然后,我们甚至可以将这个伪索引器赋给一个变量,并将其用于多个帧:

foo_columns = columns.startswith('foo')
df_1.loc[:, foo_columns]
df_2.loc[:, foo_columns]

我们甚至可以把它打印得很漂亮:

> foo_columns
<function __main__.PandasIndexer:columns.str.startswith(pat='foo')()>

我们可以使用 str访问器的任何其他方法,例如 columns.contains(r'bar\d', regex=True),同时获得有用的签名:

> columns.contains
<function __main__.PandasIndexer:columns.str.contains(pat, case=True, flags=0, na=None, regex=True)>

用这个简短的魔法密码:

from pandas import Series
from inspect import signature, Signature




class PandasIndexer:
def __init__(self, axis_name, accessor='str'):
"""
Args:
- axis_name: `columns` or `index`
- accessor: e.g. `str`, or `dt`
"""
self._axis_name = axis_name
self._accessor = accessor
self._dummy_series = Series(dtype=object)


def _create_indexer(self, attribute):
dummy_accessor = getattr(self._dummy_series, self._accessor)
dummy_attr = getattr(dummy_accessor, attribute)
name = f'PandasIndexer:{self._axis_name}.{self._accessor}.{attribute}'


def indexer_factory(*args, **kwargs):
def indexer(df):
axis = getattr(df, self._axis_name)
accessor = getattr(axis, self._accessor)
method = getattr(accessor, attribute)
return method(*args, **kwargs)


bound_arguments = signature(dummy_attr).bind(*args, **kwargs)
indexer.__qualname__ = (
name + str(bound_arguments).replace('<BoundArguments ', '')[:-1]
)
indexer.__signature__ = Signature()
return indexer


indexer_factory.__name__ = name
indexer_factory.__qualname__ = name
indexer_factory.__signature__ = signature(dummy_attr)
return indexer_factory


def __getattr__(self, attribute):
return self._create_indexer(attribute)


def __dir__(self):
"""Make it work with auto-complete in IPython"""
return dir(getattr(self._dummy_series, self._accessor))




columns = PandasIndexer('columns')

可以使用带参数 like的方法 filter:

df.filter(like='foo')

甚至你也可以尝试使用多个前缀:

temp = df.loc[:, df.columns.str.startswith(('prefix1','prefix2','prefix3'))]