在熊猫中使用Multiindex进行类似数组的操作?

问题描述

我有一个带有多索引的数据透视表,其中一层是“字段”(数据实际是什么),一层在概念上是实际的索引。我想对数据进行一些转换,例如取自然对数,并将转换后的值添加为一组行。例如:

      col   1   2   3   4 ... 100
field idx   
foo   A     7   9   2   5 ... 47
      B     8   3   4   8 ... 82
      C     3   6   1   9 ... 23
bar   A     1   17  5   2 ... 32
      B     7   5   4   8 ... 78
      C     28  6   11  3 ... 11

应成为:

      col   1   2   3   4 ... 100
field idx   
foo   A     7   9   2   5 ... 47
      B     8   3   4   8 ... 82
      C     3   6   1   9 ... 23
bar   A     1   17  5   2 ... 32
      B     7   5   4   8 ... 78
      C     28  6   11  3 ... 11
lnfoo A     <element-wise>
      B     <natural logs>
      C     <of foo>

是否有一种简单的方法可以在像这样的多索引数据透视表上执行这种数组范围的操作?特别是不需要遍历数据帧的行吗?

对Pandas来说还很陌生,很抱歉,这是一个愚蠢的问题!

解决方法

要将日志应用于完整的foo索引级别,可以使用loc一次选择所有行,然后使用np.log进行示例操作。

#example data
np.random.seed(10)
df = pd.DataFrame(np.random.randint(1,50,30).reshape(6,-1),index=pd.MultiIndex.from_product([['foo','bar'],list("ABC")],names=['field','idx']))

print(np.log(df.loc['foo']))
            0         1         2         3         4
idx                                                  
A    2.302585  3.610918  2.772589  0.000000  3.367296
B    3.258097  3.401197  3.891820  3.401197  2.197225
C    2.302585  0.000000  3.761200  3.713572  3.610918

如您所见,级别字段不在结果中,您需要使用pd.concat和字典以及要创建的级别的名称来重新创建此级别。然后再次使用pd.concat将其添加到df的末尾。

df = pd.concat([df,pd.concat({'logfoo': np.log(df.loc['foo'])},names=['field'])
               ])
print(df)
                    0          1          2          3          4
field  idx                                                       
foo    A    10.000000  37.000000  16.000000   1.000000  29.000000
       B    26.000000  30.000000  49.000000  30.000000   9.000000
       C    10.000000   1.000000  43.000000  41.000000  37.000000
bar    A    17.000000  37.000000  48.000000  12.000000  25.000000
       B    44.000000  34.000000   9.000000  37.000000  15.000000
       C    14.000000   6.000000  14.000000  26.000000  14.000000
logfoo A     2.302585   3.610918   2.772589   0.000000   3.367296
       B     3.258097   3.401197   3.891820   3.401197   2.197225
       C     2.302585   0.000000   3.761200   3.713572   3.610918
,

另一种解决方案:

tmp = df.query('field == "foo"').rename(index={'foo': 'lnfoo'})
pd.concat([df,np.log(tmp)])

您也可以轻松地将其扩展到bar

tmp = df.query('field in ("foo","bar")').rename(index={'foo': 'lnfoo','bar': 'lnbar'})
pd.concat([df,np.log(tmp)])