带有重叠组/窗口的Pandas分组。

4
我怀疑这种用法与groupby不兼容,所以也许我实际上正在寻求一种不同的模式来匹配我想要的内容。我有一个包含时间跨度事件的数据框,希望能够迭代/应用函数到每天的行上。但是如果一行从一天开始并在另一天结束,我希望该行被包含在两个日期中。
start = pd.DatetimeIndex(start='2018-02-01 21:00:00',
                         end='2018-02-05, 21:00:00', freq='6h')
df = pd.DataFrame({'start': start.date, 'end': start.shift(1).date, 'value': 1}, 
                  columns=['start', 'end', 'value'])

         start         end  value
0   2018-02-01  2018-02-02      1
1   2018-02-02  2018-02-02      1
2   2018-02-02  2018-02-02      1
3   2018-02-02  2018-02-02      1
4   2018-02-02  2018-02-03      1
5   2018-02-03  2018-02-03      1
6   2018-02-03  2018-02-03      1
7   2018-02-03  2018-02-03      1
8   2018-02-03  2018-02-04      1
9   2018-02-04  2018-02-04      1
10  2018-02-04  2018-02-04      1
11  2018-02-04  2018-02-04      1
12  2018-02-04  2018-02-05      1
13  2018-02-05  2018-02-05      1
14  2018-02-05  2018-02-05      1
15  2018-02-05  2018-02-05      1
16  2018-02-05  2018-02-06      1

因此,第一组应包含[0,...,4],然后是[4,...,8]等。实际上,事件并不均匀分布,因此每天的长度(按行计算)将不是恒定的。
我最接近的解决方法是从groupby.indices开始,并操纵分组以符合我的需求,但这感觉相当糟糕。
{k: np.append(v[0] - 1, v) for k, v in df.groupby('start').indices.items() 
 if not (len(v) == 1 and v[0] == 0)}

{Timestamp('2018-02-02 00:00:00'): array([0, 1, 2, 3, 4]),
 Timestamp('2018-02-03 00:00:00'): array([4, 5, 6, 7, 8]),
 Timestamp('2018-02-04 00:00:00'): array([ 8,  9, 10, 11, 12]),
 Timestamp('2018-02-05 00:00:00'): array([12, 13, 14, 15, 16])}

你介意能否更好地解释一下你的问题? - rpanai
2个回答

2
我相信你想要进行聚合操作。有很多方法可以选择,例如:
def e(inp):
    return [inp.index]

>>> df.groupby('end').aggregate(e)['start']

end
2018-02-02        [[0, 1, 2, 3]]
2018-02-03        [[4, 5, 6, 7]]
2018-02-04      [[8, 9, 10, 11]]
2018-02-05    [[12, 13, 14, 15]]
2018-02-06                [[16]]
Name: start, dtype: object

并且

df.groupby('start').aggregate(e)['end']
start
2018-02-01                 [[0]]
2018-02-02        [[1, 2, 3, 4]]
2018-02-03        [[5, 6, 7, 8]]
2018-02-04     [[9, 10, 11, 12]]
2018-02-05    [[13, 14, 15, 16]]
Name: end, dtype: object

现在,您可以使用这些系列进行操作,例如以下内容会产生您的输出。
merged = (df.groupby('end').aggregate(e)['start'] + df.groupby('start').aggregate(e)['end']).dropna()
merged.apply(lambda k: k[0].union(k[1]))

2018-02-02         Int64Index([0, 1, 2, 3, 4], dtype='int64')
2018-02-03         Int64Index([4, 5, 6, 7, 8], dtype='int64')
2018-02-04      Int64Index([8, 9, 10, 11, 12], dtype='int64')
2018-02-05    Int64Index([12, 13, 14, 15, 16], dtype='int64')

也许只需要使用reset_index(),那么我们就不需要自定义函数了。 - BENY
你好,我对这个话题很感兴趣。我理解了第一步的要点:按行索引定义分组。请问,如何在每个列表上应用聚合函数呢? - pierre_j

0

首先,我会将startend数据连接起来,并将结果列命名为date,如下:

df_concat = pd.DataFrame(pd.concat([df.start,df.end]),columns=['date'])

然后我会创建一个带有索引的列:

df_concat['index'] = df_concat.apply(lambda x: x.name,axis=1)

最后是一个像这样的groupbyapply
df_concat.groupby('date')['index'].apply(lambda x: sorted(set(x)))

输出结果如下:

date
2018-02-01                     [0]
2018-02-02         [0, 1, 2, 3, 4]
2018-02-03         [4, 5, 6, 7, 8]
2018-02-04      [8, 9, 10, 11, 12]
2018-02-05    [12, 13, 14, 15, 16]
2018-02-06                    [16]
Name: index, dtype: object

正如 @RafaelC 所说,有许多方法,这个是使用 apply 而不是 aggregate,我没有删除相应列表中只有一个值的日期


大家好,我也对这个话题很感兴趣。非常抱歉,在上面的回答中我提出了同样的问题。我理解了第一步:按行索引定义组。请问,如何在每个列表上应用聚合函数呢?谢谢任何帮助,祝一切顺利! - pierre_j

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接