Python Pandas - 查找具有最大聚合值的连续组

Posted

技术标签:

【中文标题】Python Pandas - 查找具有最大聚合值的连续组【英文标题】:Python Pandas - find consecutive group with max aggregate values 【发布时间】:2017-07-07 14:03:33 【问题描述】:

我有一个包含日期时间和整数的数据框

import numpy as np
import pandas as pd

df = pd.DataFrame()
df['dt'] = pd.date_range("2017-01-01 12:00", "2017-01-01 12:30", freq="1min")
df['val'] = np.random.choice(xrange(1, 100), df.shape[0])

给我

                    dt  val
0  2017-01-01 12:00:00   33
1  2017-01-01 12:01:00   42
2  2017-01-01 12:02:00   44
3  2017-01-01 12:03:00    6
4  2017-01-01 12:04:00   70
5  2017-01-01 12:05:00   94*
6  2017-01-01 12:06:00   42*
7  2017-01-01 12:07:00   97*
8  2017-01-01 12:08:00   12
9  2017-01-01 12:09:00   11
10 2017-01-01 12:10:00   66
11 2017-01-01 12:11:00   71
12 2017-01-01 12:12:00   25
13 2017-01-01 12:13:00   23
14 2017-01-01 12:14:00   39
15 2017-01-01 12:15:00   25

我怎样才能找到N-minute 组连续 dt 给我val 的最大总和?

在这种情况下,如果N=3,那么结果应该是:

                    dt  val
5  2017-01-01 12:05:00   94
6  2017-01-01 12:06:00   42
7  2017-01-01 12:07:00   97

(上面标有星号)

【问题讨论】:

【参考方案1】:

您可以使用rolling/sumnp.nanargmax 来查找与最大值的第一次出现关联的索引:

import numpy as np
import pandas as pd

df = pd.DataFrame('dt': ['2017-01-01 12:00:00', '2017-01-01 12:01:00', '2017-01-01 12:02:00', '2017-01-01 12:03:00', '2017-01-01 12:04:00', '2017-01-01 12:05:00', '2017-01-01 12:06:00', '2017-01-01 12:07:00', '2017-01-01 12:08:00', '2017-01-01 12:09:00', '2017-01-01 12:10:00', '2017-01-01 12:11:00', '2017-01-01 12:12:00', '2017-01-01 12:13:00', '2017-01-01 12:14:00', '2017-01-01 12:15:00'], 'val': [33, 42, 44, 6, 70, 94, 42, 97, 12, 11, 66, 71, 25, 23, 39, 25])
df.index = df.index*10

N = 3
idx = df['val'].rolling(window=N).sum()
i = np.nanargmax(idx) + 1
print(df.iloc[i-N : i])

打印

                     dt  val
50  2017-01-01 12:05:00   94
60  2017-01-01 12:06:00   42
70  2017-01-01 12:07:00   97

iloc uses ordinal indexing。 loc 使用基于标签的索引。前提是 i-Ni 都是有效索引,df.iloc[i-N : i] 将抓取一个窗口 (子DataFrame)长度N。相比之下,df.loc[i-N, i] 只会抓取一个 如果索引使用连续整数,则窗口长度为N。上面的例子 显示了一个 DataFrame,其中 df.loc 将无法工作,因为 df.index 有 非连续整数值。

【讨论】:

FWIW - 我无法让 rolling() 使用我的时间戳 (ops for Rolling for this dtype datetime64[ns] are not implemented) 或我的索引 ('Int64Index' object has no attribute 'rolling')。 rolling 不适用于datetime64s,因为(例如)未定义求和datetime64s。如果您希望在整数值索引上使用rolling,可以使用df.index.to_series().rolling(...)【参考方案2】:

对于简单的单个值,您可以使用如下内容:

df['total'] = df.val + df.val.shift(-1) + df.val.shift(-2)
first = df.dropna().sort('total').index[-1]
df.iloc[first:first+3]

不知道如何概括这一点...对于大多数熊猫来说,可能有一种更简单的方法,但这确实有效。

编辑:经过更多的工作,看起来滚动就是你想要的:

last = df.val.rolling(3).sum().dropna().sort_values().index[-1]

这有点不同,因为你在这里得到的索引是end,所以做完上面你想做的事

df.iloc[last-2:last+1]

我认为这可以概括。

【讨论】:

好主意。在我想要 N=100 而不是 N=3 的情况下,有没有办法参数化第一行?【参考方案3】:

您可以使用np.convolve 获取正确的起始索引并从那里开始。

def cons_max(df, N):
    max_loc = np.convolve(df.val, np.ones(N, dtype=int), mode='valid').argmax()
    return df.loc[max_loc:max_loc+N-1]

演示

>>> cons_max(df, 3)
                   dt  val
5 2017-01-01 12:05:00   94
6 2017-01-01 12:06:00   42
7 2017-01-01 12:07:00   97

>>> cons_max(df, 5)
                   dt  val
4 2017-01-01 12:04:00   70
5 2017-01-01 12:05:00   94
6 2017-01-01 12:06:00   42
7 2017-01-01 12:07:00   97
8 2017-01-01 12:08:00   12

这可以有效地在我们的输入中“滑动”内核(1 数组),并将大小为 N 的窗口中的元素相乘累加在一起。

【讨论】:

谢谢。这对于参数化 N 非常有效 这实际上是一种非常有趣的方式...可以扩展很多方式...感谢您指出这一点! 如果 df.val 是浮点数而不是 int,必须 np.ones(3,dtype=float) 还是 int 仍然可以? @philshem 是的,int 仍然可以 - 这些只是我们的乘数。 @CorleyBrigman 感谢一些食谱我不记得我从哪里了解到convolve,但不客气!

以上是关于Python Pandas - 查找具有最大聚合值的连续组的主要内容,如果未能解决你的问题,请参考以下文章

具有聚合唯一值的pyspark dataframe groupby [重复]

关于另一个 csv、pandas 上的操作(聚合最大值)的相应 csv 值

pandas-对列中具有相同值的连续行进行分组和聚合

Pandas Dataframe groupby 聚合函数和动态列的最大值和最小值之间的差异

在 Pandas Python 中聚合具有不同细节级别的数据

Python数据分析pandas之分组统计透视表