如何对熊猫中的整洁数据进行算术运算?

时间:2016-06-29 20:57:13

标签: python numpy pandas dataframe

我的“tidy”格式DataFrame(列是变量,行是观察值),包含几种不同条件的时间序列数据。我想将数据标准化为每个条件的零小时时间点。

例如,假设我提供了两种不同的animal两种不同的meal,然后每小时我记录了剩余的食物数量:

In [4]: df
Out[4]: 
   animal       meal  time  food_left
0    lion       meat     0         10
1    lion       meat     1          5
2    lion       meat     2          2
3   tiger       meat     0          5
4   tiger       meat     1          3
5   tiger       meat     2          2
6    lion  vegetable     0          5
7    lion  vegetable     1          5
8    lion  vegetable     2          5
9   tiger  vegetable     0          5
10  tiger  vegetable     1          5
11  tiger  vegetable     2          5

对于每个time点,我想通过从food_eaten时间点减去food_left来计算特定动物吃了多少食物(food_left)点零(对于那种动物和膳食),然后将结果存储在另一列中,例如:

   animal       meal  time  food_left  food_eaten
0    lion       meat     0         10           0
1    lion       meat     1          5           5
2    lion       meat     2          2           8
3   tiger       meat     0          5           0
4   tiger       meat     1          3           2
5   tiger       meat     2          2           3
6    lion  vegetable     0          5           0
7    lion  vegetable     1          5           0
8    lion  vegetable     2          5           0
9   tiger  vegetable     0          5           0
10  tiger  vegetable     1          5           0
11  tiger  vegetable     2          5           0

我正在努力弄清楚如何在Pandas中应用这种转换来产生最终数据帧(最好也是整齐的格式)。重要的是,我需要保留元数据(animalmeal等。)

最好是我想要一个能够推广到不同分组和变换的解决方案;例如,如果我想在每个时间点将老虎吃的量除以狮子在该时间点吃的量(对于给定的一餐),或者找出狮子吃多少的蔬菜而不是肉,以及等等。

我尝试过的事情:

  • groupby

    In [15]: df2 = df.set_index(['time'])
    In [16]: df2.groupby(['animal','meal']).transform(lambda x: x[0] - x)
    Out[16]: 
          food_left
    time           
    0             0
    1             5
    2             8
    0             0
    1             2
    2             3
    0             0
    1             0
    2             0
    0             0
    1             0
    2             0
    

    结果是正确的,但元数据已丢失,我无法将其重新加入原始df

  • 如果我在set_index['time', 'animal', 'meal'],那么我就不能groupby

    In [17]: df2 = df.set_index(['time','animal','meal'])
    In [19]: df2.groupby(['animal','meal']).transform(lambda x: x[0] - x)
    ---------------------------------------------------------------------------
    KeyError                                  Traceback (most recent call last)
    
    ... snip ...
    
    KeyError: 'animal'
    
  • pivot

    In [21]: data_pivot = df.pivot_table(columns=['animal','meal'],index=['time'],values='food_left')
    
    In [22]: data_norm = data_pivot.rsub(data_pivot.loc[0], axis=1)
    
    In [23]: data_norm
    Out[23]: 
    animal lion           tiger          
    meal   meat vegetable  meat vegetable
    time                                 
    0         0         0     0         0
    1         5         0     2         0
    2         8         0     3         0
    

    这有点好,我可以用meltunstack检索原始数据,但看起来不太优雅。有没有更好的办法?

2 个答案:

答案 0 :(得分:1)

您可以根据转换的数据创建一个新列,作为一行,它将是:

df['food_eaten'] = df.set_index(['time']).groupby(['animal', 'meal']).
                      transform(lambda x: x[0] - x).values

DF

    animal  meal    time    food_left   food_eaten
0   lion    meat       0          10             0
1   lion    meat       1          5              5
2   lion    meat       2          2              8
3   tiger   meat       0          5              0
4   tiger   meat       1          3              2
5   tiger   meat       2          2              3
6   lion    vegetable  0          5              0
7   lion    vegetable  1          5              0
8   lion    vegetable  2          5              0
9   tiger   vegetable  0          5              0
10  tiger   vegetable  1          5              0
11  tiger   vegetable  2          5              0

答案 1 :(得分:0)

您想使用groupbydiff

df['food_eaten'] = -df.groupby(['animal', 'meal'])['food_left'].diff()

如果您想要零而不是NaN,那么请使用fillna(),以免出现任何情况。虽然这并没有直接推广,但现在每个时间间隔内每只动物吃掉的每种食物的数量都是一样的,所以你可以在这个新的领域进行额外的计算。