python - DataFrameGroupby 对象的滚动操作

标签 python pandas pandas-groupby

我有一个 pandas 数据框,我希望对数据中的不同组执行相同的滚动操作。考虑以下包含四列的 df(请参阅问题底部以了解要构造的代码):

id      date       category   target
1    2017-01-01      'a'        0
1    2017-01-01      'b'        0
1    2017-01-21      'a'        1
1    2017-01-21      'b'        1
1    2017-10-01      'a'        0
1    2017-10-01      'b'        0
2    2017-01-01      'a'        1    
2    2017-01-01      'b'        1    
2    2017-01-21      'a'        0
2    2017-01-21      'b'        0
2    2017-10-01      'a'        0
2    2017-10-01      'b'        0

我想要的是一个操作,它为每个唯一的 id-date 对计算一个 bool 值,指示目标列是否在给定日期的 6 个月内为 1。因此,对于提供的 df,我希望得到如下所示的结果:

id      date       one_within_6m
1    2017-01-01       True
1    2017-01-21       False
1    2017-10-01       False
2    2017-01-01       False
2    2017-01-21       False
2    2017-10-01       False

我可以使用 for 循环遍历行并为每次访问提前 6 个月查看,但由于我的数据集很大,它太慢了。

所以,我想知道是否可以将日期分组并在时间窗口上进行滚动操作来查看这个?例如:

df_grouped = df.groupby(['id', 'date'])

# … do something to set date as index

# ... define some custom function

df_grouped.rolling('6m', on='target').apply(some_custom_function)

一些注意事项:

  • 在 6 个月的窗口中可以有多个“1”,这对于当前日期应该只被视为 True。

  • 在我的脑海中,some_custom_function 将检查 future 6 个月(不包括当前日期)的目标总和是否大于 1。

支持代码:

要生成此问题中使用的 DataFrame 实例:

ids = np.concatenate([np.ones(6), np.ones(6)+1])
dates = ['2017-01-01','2017-01-01','2017-01-21','2017-01-21',
         '2017-10-01','2017-10-01','2017-01-01','2017-01-01',
         '2017-01-21','2017-01-21','2017-10-01','2017-10-01']
categories = ['a','b','a','b','a','b','a','b','a','b','a','b']
targets = [0,0,1,1,0,0,1,1,0,0,0,0]

df = pd.DataFrame({'id':ids,
                   'date':dates,
                   'category':categories,
                   'target':targets})

df['date'] = pd.to_datetime(df['date'])

最佳答案

我找到了一个可行的解决方案,但它仅在每个 ID 的每个日期都是唯一的情况下才有效。我的数据就是这种情况,并进行了一些额外的处理:

new_df = df.groupby(['id','date']).mean().reset_index()

返回:

    id      date      target
0   1.0   2017-01-01    0
1   1.0   2017-01-21    1
2   1.0   2017-10-01    0
3   2.0   2017-01-01    1
4   2.0   2017-01-21    0
5   2.0   2017-10-01    0

然后我可以在 groupby 对象上使用滚动方法来获得所需的结果:

df = new_df.set_index('date')

df.iloc[::-1].groupby('id')['target'].rolling(window='180D', 
    centre=False).apply(lambda x : x[:-1].sum())

这里有两个技巧:

  1. 我颠倒了日期的顺序 (.iloc[::-1]) 以获取前瞻性窗口;这已在其他 SO questions 中提出.

  2. 我删除了总和的最后一个条目以从总和中删除“当前”日期,因此它只向前看。

第二个“hack”意味着它仅在给定 ID 的日期没有重复时才有效。

我有兴趣制定更稳健的解决方案(例如,为 id 重复日期)。

关于python - DataFrameGroupby 对象的滚动操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58628367/

相关文章:

python - 带有 WHERE 条件值列表的 pandas read_sql

python pandas - 使用for循环编辑多个DataFrame

python - 将重复行添加到 DataFrame

python - 在 Python 中,如何通过键列连接两个数组?

python - Pandas DF - 基于条件创建增量序列,无需 for 循环

python - 如何对 groupby 对象中没有时间列的基于时间的列进行排序

python - 修复 Pandas 中的 Groupby 长度

python - CVXPY:有效编写成对和的约束

python - 如何在 Python 中通过管道传输到 os.execv'd 进程的标准输入

python - 在安装了 Xcode 4 的 Mac Snow Leopard 上安装 PIL 的最佳方法是什么?