【问题标题】:Select column from DataFrame rows using a list of column labels使用列标签列表从 DataFrame 行中选择列
【发布时间】:2019-06-12 02:21:14
【问题描述】:

我有一个值列表,其中包含我想要的 pandas DataFrame 每一行的列索引。如何将此列标签列表映射到 DataFrame 的每一行?

如果我只是使用列表对 DataFrame 进行索引,则整个列表将应用于每一行,就像这样。

In [10]: df = pd.DataFrame(np.random.randn(5,2), columns=list('AB'))

In [11]: df
Out[11]: 
          A         B
0 -0.082240 -2.182937
1  0.380396  0.084844
2  0.432390  1.519970
3 -0.493662  0.600178
4  0.274230  0.132885

In[12]: selection = list('ABBAA')

In[13]: selection
Out[13]: ['A', 'B', 'B', 'A', 'A']

In[14]: df[selection]
Out[14]:
          A         B         B         A         A
0 -0.082240 -2.182937 -2.182937 -0.082240 -0.082240
1  0.380396  0.084844  0.084844  0.380396  0.380396  
2  0.432390  1.519970  1.519970  0.432390  0.432390
3 -0.493662  0.600178  0.600178 -0.493662 -0.493662
4  0.274230  0.132885  0.132885  0.274230  0.274230

选择列表中的每个元素表示要从 DataFrame 中的相应行中选择的列。在这个例子中,我想要第一行的A,第二行和第三行的B,第四行和第五行的A。事实证明,这是上述结果的对角线。我的实际 DataFrame 要大得多,我认为构建上述结果只是为了选择对角线是没有意义的。

我当然可以通过遍历行来解决这个问题,但我希望 Pandas 有一个内置的方法来做到这一点。我正在寻找获得以下结果的方法。

In[15]: df <do something> selection
Out[15]:
0 -0.082240
1  0.084844
2  1.519970
3 -0.493662
4  0.274230

【问题讨论】:

  • 你只需要选择的对角线值吗?
  • 是的,selection 列表的每个元素都表示我想从不同行中获取哪一列。

标签: python pandas dataframe


【解决方案1】:

如果您首先根据选择选择列然后获取对角线值,则您将数据框切片两次。您可以改用 lookup,它返回一个数组,其中包含与每个 (row, col) 对相对应的值。

df.lookup(df.index, selection)

array([-0.08224 ,  0.084844,  1.51997 , -0.493662,  0.27423 ])

如果你想要 Pandas 系列形式的数据,

pd.Series(df.lookup(df.index, selection))

0   -0.082240
1    0.084844
2    1.519970
3   -0.493662
4    0.274230

【讨论】:

  • 按原样,这仅在 DataFrame 索引匹配 np.arange(len(selection)) 时才有效。最好直接使用df.index 作为df.lookup() 的第一个输入。
  • @StevenC.Howell,我同意。我假设索引是从 0 开始的默认 pandas 索引
  • 这通常不是一个安全的假设,因为一旦索引不是默认值,它就会中断。这是我的简单示例,但通常索引可能更具描述性。只使用df.index 会更安全,并且不需要额外的函数调用。
  • 这样就万无一失了,df.lookup(df.index[:len(selection)], selection)
  • 在我的问题中,我声明该列表的每一行都有一个值。我正在使用它为 DataFrame 创建一个新列。不需要按选择列表的长度对索引进行切片。 df.lookup(df.index, selection) 是一个干净、简单、易于理解的解决方案。谢谢!
【解决方案2】:

我只能想到numpy的方法

pd.Series(df.values[df.index,df.columns.get_indexer(selection)])
Out[563]: 
0   -0.082240
1    0.084844
2    1.519970
3   -0.493662
4    0.274230
dtype: float64

【讨论】:

  • 这与接受的答案一样有效。在我的实际 DataFrame 上计时甚至给出了相同的时间。
【解决方案3】:

使用reindex:

df.reindex(selection, axis=1)

输出:

          A         B         B         A         A
0  0.065447 -1.890299 -1.890299  0.065447  0.065447
1  0.389780  0.301049  0.301049  0.389780  0.389780
2  0.484159 -1.311432 -1.311432  0.484159  0.484159
3 -0.209745 -2.233050 -2.233050 -0.209745 -0.209745
4 -0.093495 -1.527827 -1.527827 -0.093495 -0.093495

然后,使用np.eyemask

df.reindex(selection, axis=1).mask(np.eye(5) == 0).stack()

输出:

0  A    0.065447
1  B    0.301049
2  B   -1.311432
3  A   -0.209745
4  A   -0.093495
dtype: float64

【讨论】:

    【解决方案4】:

    IIUC,试试这个

    df[selection].values.diagonal()
    

    如果您需要Series 的形式如您所说,请执行 -

    pd.Series(df[selection].values.diagonal())
    

    【讨论】:

      猜你喜欢
      • 2015-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-23
      • 2018-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多