【问题标题】:Python Pandas - find consecutive group with max aggregate valuesPython Pandas - 查找具有最大聚合值的连续组
【发布时间】: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

(上面标有星号)

【问题讨论】:

    标签: python python-2.7 pandas numpy grouping


    【解决方案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 indexingloc 使用基于标签的索引。前提是 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,但不客气!
    猜你喜欢
    • 2018-03-03
    • 2015-07-27
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 2013-09-13
    • 2016-05-20
    相关资源
    最近更新 更多