【问题标题】:get dataframe slice with list of column names where not all columns are in dataframe获取包含列名列表的数据框切片,其中并非所有列都在数据框中
【发布时间】:2016-10-26 06:48:27
【问题描述】:

考虑df

df = pd.DataFrame(np.ones((2, 3)), columns=list('abc'))
df

col_list = list('bcd')

df[col_list]

产生错误

KeyError: "['d'] not in index"

如何获得尽可能多的列?

【问题讨论】:

    标签: python pandas numpy


    【解决方案1】:

    使用Index.intersection()怎么样?

    In [69]: df[df.columns.intersection(col_list)]
    Out[69]:
         b    c
    0  1.0  1.0
    1  1.0  1.0
    
    In [70]: df.columns
    Out[70]: Index(['a', 'b', 'c'], dtype='object')  # <---------- Index
    

    时间:

    In [21]: df_ = pd.concat([df] * 10**5, ignore_index=True)
    
    In [22]: df_.shape
    Out[22]: (200000, 3)
    
    In [23]: df.columns
    Out[23]: Index(['a', 'b', 'c'], dtype='object')
    
    In [24]: col_list = list('bcd')
    
    In [28]: %timeit df_[df_.columns.intersection(col_list)]
    100 loops, best of 3: 6.24 ms per loop
    
    In [29]: %timeit df_[[col for col in col_list if col in df_.columns]]
    100 loops, best of 3: 5.69 ms per loop
    

    让我们在转置的 DF(3 行,200K 列)上测试它:

    In [30]: t = df_.T
    
    In [31]: t.shape
    Out[31]: (3, 200000)
    
    In [32]: t
    Out[32]:
       0       1       2       3       4        ...    199995  199996  199997  199998  199999
    a     1.0     1.0     1.0     1.0     1.0   ...       1.0     1.0     1.0     1.0     1.0
    b     1.0     1.0     1.0     1.0     1.0   ...       1.0     1.0     1.0     1.0     1.0
    c     1.0     1.0     1.0     1.0     1.0   ...       1.0     1.0     1.0     1.0     1.0
    
    [3 rows x 200000 columns]
    
    In [33]: col_list=[-10, -20, 10, 20, 100]
    
    In [34]: %timeit t[t.columns.intersection(col_list)]
    10 loops, best of 3: 52.8 ms per loop
    
    In [35]: %timeit t[[col for col in col_list if col in t.columns]]
    10 loops, best of 3: 103 ms per loop
    

    结论:几乎总是列表理解在较小的列表中获胜,而 Pandas/NumPy 在较大的数据集中获胜...

    【讨论】:

      【解决方案2】:

      怎么样:

      df[[col for col in list('bcd') if col in df.columns]]
      

      这会产生:

           b    c
      0  1.0  1.0
      1  1.0  1.0
      

      【讨论】:

        【解决方案3】:

        Index 对象支持isin

        In [4]:    
        col_list = list('bcd')
        df.ix[:,df.columns.isin(col_list)]
        
        Out[4]:
           b  c
        0  1  1
        1  1  1
        

        因此,这将针对传入的列表生成现有列的布尔掩码

        时间

        In [5]:
        df_ = pd.concat([df] * 10**5, ignore_index=True)
        %timeit df_[df_.columns.intersection(col_list)]
        %timeit df_[[col for col in col_list if col in df_.columns]]
        %timeit df_.ix[:,df_.columns.isin(col_list)]
        
        100 loops, best of 3: 12.8 ms per loop
        100 loops, best of 3: 18.6 ms per loop
        10 loops, best of 3: 26.6 ms per loop
        

        这是最慢的方法,但字符较少,可能更容易理解

        【讨论】:

        • 我问这个问题是因为当我开始使用 pandas 时,这是让我烦恼的事情之一。我认为这个答案非常有用,我怀疑很多人会选择它而不是其他答案。
        猜你喜欢
        • 2015-12-29
        • 2020-07-29
        • 2021-12-29
        • 2016-11-02
        • 2019-10-31
        • 2020-07-08
        • 2021-11-06
        • 2019-08-11
        • 1970-01-01
        相关资源
        最近更新 更多