【问题标题】:Pandas combining slices and list to select columnsPandas 结合切片和列表来选择列
【发布时间】:2021-04-10 14:55:48
【问题描述】:

假设 DataFrame df 具有以下列:['c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7']

我们可以使用切片或列表来选择一些列:

  • 带切片:df.loc[:, 'c1':'c4']
  • 有列表:df.loc[:, ['c1','c4','c6']]

如果我们要选择['c1', 'c4', 'c5', 'c6', 'c7']

无法执行以下操作:['c1', 'c4':'c7']。但是你看到了这个想法,是否可以将列表和切片结合起来?

【问题讨论】:

标签: python pandas


【解决方案1】:

您可以将 np.r_ 与列标题索引一起使用,如下所示:

df = pd.DataFrame(np.arange(49).reshape(7,-1), columns=[f'c{i}' for i in range(1,8)])
df.loc[:, df.columns[np.r_[0,3:7]]]

输出:

   c1  c4  c5  c6  c7
0   0   3   4   5   6
1   7  10  11  12  13
2  14  17  18  19  20
3  21  24  25  26  27
4  28  31  32  33  34
5  35  38  39  40  41
6  42  45  46  47  48

【讨论】:

  • 值得指出的是,这仅适用于数字。我认为这不是 OP 所要求的。
  • @noah 我正在使用数字索引来获取列的适当字符串名称,但是不,我同意我认为没有办法将字符串切片与字符串位置一起使用。
  • 啊,第一眼就错过了
【解决方案2】:

可以通过以下方式直接使用列名:

df.loc[:, ['c1'] + ['c{}'.format(i) for i in range(3, 8)]]

【讨论】:

    【解决方案3】:

    如果您重新考虑输入的方式,这里有一个简单的方法。按原样存储各个标签,然后制作切片元组。一个简单的辅助函数将其解析为元组之间的所有标签。

    这里没有对要切片的范围进行硬编码,一切都基于您最初提供的标签。

    样本数据

    import pandas as pd
    import numpy as np
    
    df = pd.DataFrame(np.random.normal(0, 1, (1, 10)),
                      columns = ['c1', 'c3', 'c4', 'foo', 'bar', 'c5', 'c6',
                                 'c7', 'c8', 'c9'])
    
    my_slice = ['c1', ('c4', 'c7')]
    

    def create_labels(columns, my_slice):
        """
        columns: pd.Index
        my_slice: list of labels, or tuple if slice
        """
        labels = []
        for x in my_slice:
            if isinstance(x, tuple):
                labels.extend(columns[columns.get_loc(x[0]): 
                                      columns.get_loc(x[1])+1])
            else:
                labels.append(x)   
        return labels
            
    
    create_labels(df.columns, my_slice)
    #['c1', 'c4', 'foo', 'bar', 'c5', 'c6', 'c7']
    

    【讨论】:

      【解决方案4】:

      您可以为列构建自定义索引生成工厂。这基本上只是存储对数据框列的引用,然后对任何切片执行查找。您只需将其放在所需的列列表前面即可使用它。

      即:只需将df.loc[: ['c1', 'c4':'c7']] 替换为df.loc[:, ci['c1', 'c4':'c7']] 即可使用它:

      import pandas as pd
      
      df = pd.DataFrame([list(range(7))], columns=[f'c{i}' for i in range(1, 8)])
      
      df
      # return:
         c1  c2  c3  c4  c5  c6  c7
      0   0   1   2   3   4   5   6
      
      
      class ColumnIndexer:
          def __init__(self, df):
              self._df_cols_ref = df.columns
      
          def __getitem__(self, ix):
              if not isinstance(ix, tuple):
                  ix = (ix,)
              indices = []
              for i in ix:
                  if isinstance(i, slice):
                      if i.start is None:
                          left = 0
                      else:
                          left = self._df_cols_ref.get_slice_bound(
                              i.start, 'left', 'loc')
                      if i.stop is None:
                          right = len(self._df_cols_ref) + 1
                      else:
                          right = df.columns.get_slice_bound(
                              i.stop, 'right', 'loc')
                      indices.extend(self._df_cols_ref[left: right])
                  else:
                      indices.append(i)
              return indices
      

      使用对象索引器:

      ci = ColumnIndexer(df)
      
      df.loc[:, ci['c1', 'c4':'c7']]
      # returns:
         c1  c4  c5  c6  c7
      0   0   3   4   5   6
      

      【讨论】:

        猜你喜欢
        • 2016-01-07
        • 2017-01-13
        • 2017-08-11
        • 2017-03-10
        • 2017-01-01
        • 2018-10-13
        • 2018-10-07
        • 2010-12-14
        • 1970-01-01
        相关资源
        最近更新 更多