【问题标题】:How to select columns from dataframe by regex如何通过正则表达式从数据框中选择列
【发布时间】:2015-08-28 18:43:21
【问题描述】:

我在 python pandas 中有一个数据框。数据框的结构如下:

   a    b    c    d1   d2   d3 
   10   14   12   44  45    78

我想选择以 d 开头的列。有没有一种简单的方法可以在 python 中实现这一点。

【问题讨论】:

    标签: python python-2.7 pandas


    【解决方案1】:

    您可以使用列表推导来遍历 DataFrame df 中的所有列名,然后只选择以“d”开头的那些。

    df = pd.DataFrame({'a': {0: 10}, 'b': {0: 14}, 'c': {0: 12},
                       'd1': {0: 44}, 'd2': {0: 45}, 'd3': {0: 78}})
    

    使用列表推导遍历数据框中的列并返回它们的名称(下面的c 是表示列名称的局部变量)。

    >>> [c for c in df]
    ['a', 'b', 'c', 'd1', 'd2', 'd3']
    

    然后只选择那些以'd'开头的。

    >>> [c for c in df if c[0] == 'd']  # As an alternative to c[0], use c.startswith(...)
    ['d1', 'd2', 'd3']
    

    最后,将此列列表传递给 DataFrame。

    df[[c for c in df if c.startswith('d')]]
    >>> df
       d1  d2  d3
    0  44  45  78
    

    ================================================ ==============================

    时间(2018 年 2 月每 cmets 来自 devinbost 声称这种方法很慢...)

    首先,让我们创建一个包含 30k 列的数据框:

    n = 10000
    cols = ['{0}_{1}'.format(letters, number) 
            for number in range(n) for letters in ('d', 't', 'didi')]
    df = pd.DataFrame(np.random.randn(3, n * 3), columns=cols)
    >>> df.shape
    (3, 30000)
    
    >>> %timeit df[[c for c in df if c[0] == 'd']]  # Simple list comprehension.
    # 10 loops, best of 3: 16.4 ms per loop
    
    >>> %timeit df[[c for c in df if c.startswith('d')]]  # More 'pythonic'?
    # 10 loops, best of 3: 29.2 ms per loop
    
    >>> %timeit df.select(lambda col: col.startswith('d'), axis=1)  # Solution of gbrener.
    # 10 loops, best of 3: 21.4 ms per loop
    
    >>> %timeit df.filter(regex=("d.*"))  # Accepted solution.
    # 10 loops, best of 3: 40 ms per loop
    

    【讨论】:

    • 我没有收到代码。里面的c是什么。您是否测试过代码,请提供一些解释。
    • c.startswith('d') 可能更 Pythonic。不管怎样,我喜欢这个!
    • 这非常慢。矢量化方法将是非常受欢迎的。
    • @devinbost 您的请求是一个可悲的廉价镜头,并且是在 OP 提出问题近两年后提出的。 OP问“有没有一种简单的方法可以在python中实现这一点”,我的回答在大多数情况下都有效。如果您有一个 特定 要求,该要求调用具有大量列或具有许多数据框的数据框,那么我建议您提出更具体的问题。
    • @devinbost,您发布的链接指的是优化row-wise,这篇文章明确询问了选择column-wise,所以你的咆哮关于社区的最佳实践真的不合时宜。对于常见的数据分析,列数很少会超过一百,也不需要向量化。
    【解决方案2】:

    你可以这样使用DataFrame.filter

    import pandas as pd
    
    df = pd.DataFrame(np.array([[2,4,4],[4,3,3],[5,9,1]]),columns=['d','t','didi'])
    >>
       d  t  didi
    0  2  4     4
    1  4  3     3
    2  5  9     1
    
    df.filter(regex=("d.*"))
    
    >>
       d  didi
    0  2     4
    1  4     3
    2  5     1
    

    想法是通过regex选择列

    【讨论】:

      【解决方案3】:

      使用select:

      import pandas as pd
      
      df = pd.DataFrame([[10, 14, 12, 44, 45, 78]], columns=['a', 'b', 'c', 'd1', 'd2', 'd3'])
      
      df.select(lambda col: col.startswith('d'), axis=1)
      

      结果:

         d1  d2  d3
      0  44  45  78
      

      如果您对正则表达式不满意,这是一个很好的解决方案。

      【讨论】:

      • 请注意 select 现在已被弃用
      【解决方案4】:

      你也可以使用

      df.filter(regex='^d')
      

      【讨论】:

      • 如果我想过滤以d结尾的列?
      【解决方案5】:

      尤其是在更大的数据集上,矢量化方法实际上要快得多(超过两个数量级)并且可读性要好得多。 我提供截图作为证据。 (注意:除了我在底部写的最后几行以矢量化方法阐明我的观点外,其他代码来自@Alexander 的答案。)

      这是供参考的代码:

      import pandas as pd
      import numpy as np
      n = 10000
      cols = ['{0}_{1}'.format(letters, number) 
              for number in range(n) for letters in ('d', 't', 'didi')]
      df = pd.DataFrame(np.random.randn(30000, n * 3), columns=cols)
      
      %timeit df[[c for c in df if c[0] == 'd']]
      
      %timeit df[[c for c in df if c.startswith('d')]]
      
      %timeit df.select(lambda col: col.startswith('d'), axis=1)
      
      %timeit df.filter(regex=("d.*"))
      
      %timeit df.filter(like='d')
      
      %timeit df.filter(like='d', axis=1)
      
      %timeit df.filter(regex=("d.*"), axis=1)
      
      %timeit df.columns.map(lambda x: x.startswith("d"))
      
      columnVals = df.columns.map(lambda x: x.startswith("d"))
      
      %timeit df.filter(columnVals, axis=1)
      

      【讨论】:

      • 我无法使用您的方法来过滤我的数据框,使用最后两行我的结果是空的...没有列...这种方法仍然有效吗?
      • @RachOdwyer 我认为它应该可以工作,除非他们推出了一项重大更改。如果是这种情况,请告诉我。
      • 有点晚了:你可以使用 df.loc[:, columnVals] 代替
      【解决方案6】:

      您可以使用startswith 方法与索引(本例中为列):

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

      match 使用正则表达式:

      df.loc[:, df.columns.str.match('^d')]
      

      【讨论】:

        【解决方案7】:

        获取以 [abc] 开头直到 '_' 的列名的任何子字符串,删除所有不匹配项 (NA),删除重复项并排序。

        df.columns.str.extract(r'([abc].*_)', expand=False).dropna().drop_duplicates().sort_values()
        

        【讨论】:

          猜你喜欢
          • 2012-11-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-10
          • 2015-08-22
          • 2016-01-24
          • 1970-01-01
          相关资源
          最近更新 更多