【问题标题】:How to implement non overlapping rolling functionality on MultiIndex DataFrame如何在 MultiIndex DataFrame 上实现非重叠滚动功能
【发布时间】:2016-07-28 21:46:40
【问题描述】:

到目前为止,我找到了this question,但由于以下事实,它并没有解决我的问题:

  1. 我有一个 MultiIndex DataFrame
  2. 内层每个外层的数据量不同,所以我不能用len()

我有以下数据框

Outer Inner    Value        
  A     1     2.000000
  A     2     4.000000
  A     3     6.000000
  A     4     8.000000
  B     1     3.000000
  B     2     6.000000
  B     3     9.000000
  B     4     12.000000
  B     5     15.000000

我想以不重叠的方式对每个 outer 的最后两个值求和。所以对于A,我想对inner 的3 + 4、1 + 2 求和。对于B,我想对inner 的4 + 5、2 + 3 求和。请注意,假设成对总和从最后一个值开始。导致

Outer Inner    Value        
  A     2     6.000000
  A     4    14.000000
  B     3    15.000000
  B     5    27.000000

【问题讨论】:

  • B1 会发生什么?
  • 我猜它被丢弃了,因为没有 2 组。但任何其他处理都是可以接受的。
  • 所以你开始总结最后一个值的对?我会认为B5应该被丢弃
  • 哦,有道理。但理想情况下,我想从最后一个开始,将 B1 排除在外。
  • 但是那里的逻辑是什么?你怎么能从头开始,把 B1 排除在外?

标签: python python-3.x pandas


【解决方案1】:

具有自定义重采样功能的 Groupby

您很可能需要自定义重采样才能执行此操作。这有点hacky,但可能有用。

  1. 删除所有MulitIndexing 只处理常规列groupby()s
  2. groupby() 'Outer'.apply() 每个组的自定义函数
  3. 自定义函数需要一组
    1. 确定组的偶数长度
    2. 向后选择该长度
    3. 将索引转换为秒
    4. 通过resample(...).sum()每两个样本重新采样一次DataFrame
    5. resample(...).last() 每两个对Inner 列重新采样一次以保留原始索引号
    6. 将索引转换回'Inner'
  4. 即使我们删除了MultiIndexMultiIndex 仍由groupby(...).apply() 返回

注意: rolling 存在问题,因为它滑动 穿过值而不是单步穿过​​ 值(在非重叠方法中)。使用 resample 可以做到这一点。重采样是基于时间的,索引需要以秒表示。

示例

import math
import pandas as pd

df = pd.DataFrame({
    'Outer': ['A','A','A','A','B','B','B','B','B'],
    'Inner': [1,2,3,4,1,2,3,4,5],
    'Value': [2.00,4.00,6.00,8.00,3.00,6.00,9.00,12.00,15.00]
})

def f(g):
    even_length = int(2.0 * math.floor(len(g) / 2.0))
    every_two_backwards = g.iloc[-even_length:]
    every_two_backwards.index = pd.TimedeltaIndex(every_two_backwards.index * 1000000000.0)
    resample_via_sum = every_two_backwards.resample('2s').sum().dropna()
    resample_via_sum['Inner'] = every_two_backwards.resample('2s').last()
    resample_via_sum = resample_via_sum.set_index('Inner')

    return resample_via_sum

resampled_df = df.groupby(['Outer']).apply(f)

print resampled_df

             Value
Outer Inner       
A     2.0      6.0
      4.0     14.0
B     3.0     15.0
      5.0     27.0

【讨论】:

  • 只有一个问题,'2s 是什么意思?我正在为其他间隔调整函数以进行测试
  • '2s' 只是意味着重新采样 2 秒。
  • 由于我们将索引转换为秒以使用resample,因此我们在 内重新采样
  • 这有意义吗?记住要在 both 处进行更改。您可能希望将其设为变量 (resample_step = '2s'),以便您可以在这两个地方引用它。例如resample(resample_step).
  • 你不应该在那里改变它。这只是为了确定组的偶数长度。
【解决方案2】:

好的,卷起袖子,这需要一些工作:

new_level0 = []
new_level1 = []
new_values  = []

for level0 in df.index.levels[0].values:
    #this will loop with A and B

    #retrieve the values
    level1_values = df[level0]['Value'].values
    #retrieve the index, we will keep some of the values of it
    level1_index  = df[level0].index.values


    #split the values into two vectors
    #reverse so that it starts pairing values from the end
    level1_even = [i for enum,i in enumerate(level1_values) if enum%2==0].reverse()
    level1_odd =  [i for enum,i in enumerate(level1_values) if enum%2==1].reverse()
    #
    #
    #sum and reverse again to bring back to normal order
    summed = [i+j for i,j in zip(level1_even,level1_odd)]
    summed.reverse()
    #
    #
    #now that we have the values, lets get the index that we need
    #again, reverse so that we keep the right one
    level1_index.reverse()

    #keep only the multiples of two, then undo the reverse
    new_index = [i for enum,i in enumerate(level1_values) if enum%2==0].reverse()

    #now store the combination of level0, level1 and value
    new_level0 += [level0 for i in summed]
    new_level1 += new_index
    new_values += summed

    #your final structure is:
    s = pd.Series(summed, index= [new_level0, new_level1])    

【讨论】:

    猜你喜欢
    • 2014-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-23
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多