将具有多个列的计算结果添加到具有MultiIndex列的Pandas DataFrame

时间:2015-10-08 21:10:27

标签: python pandas multi-index

我有一个像这样的DataFrame:

In [10]: df.head()
Out[10]: 
      sand              silt              clay             rho_b  ...      n  \
        5     25    60    5     25    60    5     25    60    5   ...     60   
STID                                                              ...          
ACME  73.0  60.3  52.5  19.7  23.9  25.9   7.2  15.7  21.5  1.27  ...   1.32   
ADAX  61.1  51.1  47.6  22.0  25.4  24.6  16.9  23.5  27.8  1.01  ...   1.25   
ALTU  23.8  17.8  14.3  40.0  45.2  40.9  36.2  37.0  44.8  1.57  ...   1.18   
ALV2  33.3  21.2  19.8  31.4  29.7  29.8  35.3  49.1  50.5  1.66  ...   1.20   
ANT2  55.6  57.5  47.7  34.9  31.1  26.8   9.4  11.3  25.5  1.49  ...   1.29  

因此,对于每个STID(例如ACME,ADAX,ALTU),在三个深度(5,25,60)定义了一些属性(例如沙子,淤泥,粘土)。

这种结构使得在每个STID上进行每深度计算变得非常容易,例如:

In [12]: (df['sand'] + df['silt']).head()
Out[12]: 
        5     25    60
STID                  
ACME  92.7  84.2  78.4
ADAX  83.1  76.5  72.2
ALTU  63.8  63.0  55.2
ALV2  64.7  50.9  49.6
ANT2  90.5  88.6  74.5

如何将计算结果整齐地合并到DataFrame中?例如,如果我想调用上述计算结果'notclay'

In [13]: df['notclay'] = df['sand'] + df['silt']
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-13-a30bd9ba99c3> in <module>()
----> 1 df['notclay'] = df['sand'] + df['silt']

<snip>

ValueError: Wrong number of items passed 3, placement implies 1

预计将为结果中的每列定义三列,而不仅仅是一列'notclay'列。

我确实有一个使用严格作业的解决方案,但我对它不是很满意:

In [21]: df[[('notclay', 5), ('notclay', 25), ('notclay', 60)]] = df['sand'] + df['silt']

In [22]: df['notclay'].head()
Out[22]: 
        5     25    60
STID                  
ACME  92.7  84.2  78.4
ADAX  83.1  76.5  72.2
ALTU  63.8  63.0  55.2
ALV2  64.7  50.9  49.6
ANT2  90.5  88.6  74.5

我有许多其他计算与此类似,并且每次使用严格的赋值似乎都很乏味。我猜测那里有更好的&#34;对&#34;这样做的方式。我认为add a field in pandas dataframe with MultiIndex columns可能包含答案,但我不太了解解决方案(甚至是Panel是什么以及它是否可以帮助我)。

编辑:我尝试没有工作的东西,使用concat预先添加类别:

In [36]: concat([df['sand'] + df['silt']], axis=1, keys=['notclay']).head()
Out[36]: 
     notclay            
          5     25    60
STID                    
ACME    92.7  84.2  78.4
ADAX    83.1  76.5  72.2
ALTU    63.8  63.0  55.2
ALV2    64.7  50.9  49.6
ANT2    90.5  88.6  74.5

In [37]: df['notclay'] = concat([df['sand'] + df['silt']], axis=1, keys=['notclay'])
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)

<snip>

ValueError: Wrong number of items passed 3, placement implies 1

同上ValueError如上所述。

1 个答案:

答案 0 :(得分:1)

根据您的口味,这可能是一个更好的方法,仍然使用concat:

In [53]: df
Out[53]: 
       blah                           foo                    
          1         2         3         1         2         3
a  0.351045  0.044654  0.855627  0.839725  0.675183  0.325324
b  0.610374  0.394499  0.924708  0.924303  0.404475  0.885368
c  0.116418  0.487866  0.190669  0.283535  0.862869  0.346477
d  0.771014  0.204143  0.143449  0.848520  0.887373  0.220083
e  0.103268  0.306820  0.277125  0.627272  0.631019  0.386406

In [54]: newdf
Out[54]: 
          1         2         3
a  0.433377  0.806679  0.976298
b  0.593683  0.217415  0.086565
c  0.716244  0.908777  0.180252
d  0.031942  0.074283  0.745019
e  0.651517  0.393569  0.861616

In [56]: newdf.columns=pd.MultiIndex.from_product([['bar'], newdf.columns])

In [57]: pd.concat([df, newdf], axis=1)
Out[57]: 
       blah                           foo                           bar  \
          1         2         3         1         2         3         1   
a  0.351045  0.044654  0.855627  0.839725  0.675183  0.325324  0.433377   
b  0.610374  0.394499  0.924708  0.924303  0.404475  0.885368  0.593683   
c  0.116418  0.487866  0.190669  0.283535  0.862869  0.346477  0.716244   
d  0.771014  0.204143  0.143449  0.848520  0.887373  0.220083  0.031942   
e  0.103268  0.306820  0.277125  0.627272  0.631019  0.386406  0.651517   


          2         3  
a  0.806679  0.976298  
b  0.217415  0.086565  
c  0.908777  0.180252  
d  0.074283  0.745019  
e  0.393569  0.861616 

为了将其存储到原始数据帧中,您只需在最后一行中分配它:

In [58]: df = pd.concat([df, newdf], axis=1)