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

2025-03-18 08:55:00
admin
原创
90
摘要:问题描述:我有一个数据框: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...

问题描述:

我有一个数据框:

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

另一种方法是从列创建一个系列并使用矢量化的 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:

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

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


解决方案 4:

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

df.filter(like='foo')

解决方案 5:

就我而言,我需要一个前缀列表

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

解决方案 6:

您可以在此处尝试使用正则表达式来过滤以“foo”开头的列

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

如果你需要在列中包含字符串 foo,那么

df.filter(regex='foo*')

是合适的。

对于下一步,您可以使用

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

过滤掉'foo*'列的值之一为 1 的行。

解决方案 7:

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

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

如果您要选择的列并非全部都以 开头,那么这将非常有用foo。此方法选择包含子字符串的所有列foo,并且可以将其放置在列名称的任何位置。

本质上,我.startswith()用替换了.contains()

解决方案 8:

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

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

解决方案 9:

选择所需条目的另一种方法是使用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)

因此,如果某列不是以 开头fooFalse则返回,因此不会选择该列。

如果你只是想返回所有包含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

解决方案 10:

我不喜欢其他解决方案要求我们引用 DataFrame 两次;如果您只有一个名为的框架df,那么可能没问题,但情况往往并非如此(并且您的实际名称可能要长得多)。让我们滥用 pandas 索引功能来减少输入,并使代码更具可读性。没有什么可以阻止我们使用类似这样的方法:

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'bard', 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')

解决方案 11:

我的解决方案。这可能会降低性能:

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

解决方案 12:

一个选项是使用pyjanitor 的选择功能:

# pip install pyjanitor
import janitor 
import pandas as pd

df.select(columns='foo*')
Out[32]: 
   foo.aa  foo.fighters  foo.bars  foo.fox foo.manchu
0     1.0           0.0         0        2         NA
1     2.1           1.0         0        4          0
2     NaN           NaN         0        1          0
3     4.7           0.0         0        0          0
4     5.6           0.0         0        0          0
5     6.8           0.0         1        5          0

要获得行和列的答案:

df.select(rows=df.select(columns='foo*').eq(1).any(axis=1), columns='foo*')
Out[36]: 
   foo.aa  foo.fighters  foo.bars  foo.fox foo.manchu
0     1.0           0.0         0        2         NA
1     2.1           1.0         0        4          0
2     NaN           NaN         0        1          0
5     6.8           0.0         1        5          0

当然,您只需将布尔值传递给.loc

df.loc[df.select(columns='foo*').eq(1).any(axis=1)]
Out[38]: 
   foo.aa  foo.fighters  foo.bars  bar.baz  foo.fox nas.foo foo.manchu
0     1.0           0.0         0      5.0        2      NA         NA
1     2.1           1.0         0      5.0        4       0          0
2     NaN           NaN         0      6.0        1       1          0
5     6.8           0.0         1      6.8        5       0          0
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   4089  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2787  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   105  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   126  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   108  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用