如何将不同长度的时间窗口应用于熊猫数据框

时间:2019-10-12 16:53:54

标签: python pandas numpy dataframe

我有以下数据框,每行代表一次销售交易:

startDate           INDEX_250   priceDeal
2013-05-02 00:00:00 9312.000    255000.000
2013-09-17 00:00:00 11121.000   368209.000
2013-10-09 00:00:00 11121.000   254000.000
2013-11-14 00:00:00 11121.000   520000.000
2013-11-22 00:00:00 11121.000   201000.000
2014-02-05 00:00:00 11121.000   260000.000
2014-02-28 00:00:00 11121.000   425000.000
2014-03-01 00:00:00 11121.000   315000.000
2014-03-11 00:00:00 9312.000    427000.000
2014-04-27 00:00:00 9312.000    138070.000
2014-06-20 00:00:00 9312.000    270000.000
2014-07-21 00:00:00 9312.000    282000.000
2014-07-31 00:00:00 9312.000    308806.350
2014-09-27 00:00:00 11121.000   170000.000
2014-10-05 00:00:00 11121.000   171658.220
2014-10-11 00:00:00 11121.000   292000.000
2014-10-13 00:00:00 11121.000   125000.000
2014-10-30 00:00:00 9312.000    95000.000
2014-11-18 00:00:00 9312.000    158942.280
2015-01-25 22:00:00 11121.000   238829.370
2015-03-11 00:00:00 11121.000   180695.960
2015-03-14 00:00:00 9312.000    320932.860
2015-03-21 00:00:00 11121.000   139872.000
2015-09-04 00:00:00 11121.000   140000.000
2015-09-09 00:00:00 9312.000    235000.000

我想查看在前30天nrTargets_gr_250_30和60天nrTargets_gr_250_60中,第一笔销售交易INDEX_250中的每笔交易(按2013-09-17}发生了多少笔交易。示例数据集仅适用于一个INDEX_250,但也有其他索引号,建议按以下顺序输出:

      startDate  INDEX_250  nrTargets_gr_250_30 nrTargets_gr_250_60
      2013-10-17    11121   2.000               2.000
      2013-11-16    11121   1.000               3.000
      2013-12-16    11121   1.000               2.000
      2014-01-15    11121   0.000               1.000
      2014-02-14    11121   1.000               1.000
      2014-03-16    11121   2.000               3.000
      2014-04-15    11121   0.000               2.000
      2014-10-12    11121   3.000               3.000
      2014-11-11    11121   1.000               4.000
      2014-12-11    11121   0.000               1.000
      2015-02-09    11121   1.000               1.000
      2015-03-11    11121   0.000               1.000
      2015-04-10    11121   2.000               2.000
      2015-05-10    11121   0.000               2.000
      2015-09-07    11121   1.000               1.000
      2015-10-07    11121   0.000               1.000
      2016-02-04    11121   1.000               1.000
      2016-03-05    11121   0.000               1.000
      2017-01-29    11121   1.000               1.000

1 个答案:

答案 0 :(得分:1)

我注意到您希望将 startDate 更改为各自的末尾 从开始日期算起30天。

另一个细节是您希望结果按 INDEX_250 分组- 之前(在两个时期内)有多少笔交易 INDEX_250 相同值。

还要注意,滚动计算可以在窗口上执行 包含来自多个未来期的行,而您希望 上一个前30天或60天的交易数量,以及 滚动不允许出现负数。

这就是为什么我采用不同于“普通”滚动的方法的原因。

从辅助变量开始:

td30 = pd.Timedelta('30D')
dRng = pd.date_range(start='2013-09-17', end=df.startDate.max() + td30,
    freq='30D', closed='left')

然后定义以下计算两个目标的函数:

def targets(grp):
    grp['Prd'] = grp.startDate.apply(lambda x: dRng.asof(x) + td30)
    grp.set_index('Prd', inplace=True)
    trg30 = grp.groupby(level=0).INDEX_250.count()\
        .rename('nrTargets_gr_250_30').reindex(dRng, fill_value=0)
    trg60 = trg30.rolling(2).sum().rename('nrTargets_gr_250_60')\
        .fillna(0, downcast='infer')
    trg30 = trg30[trg30 > 0]
    trg60 = trg60[trg60 > 0]
    return trg30.to_frame().join(trg60, how='outer')\
        .fillna(0, downcast='infer').rename_axis('startDate')

应用它并重置索引(按此顺序,以对列进行正确排序):

df2 = df[df.startDate >= '2013-09-17'].groupby('INDEX_250')\
    .apply(targets).reset_index(level=[0]).reset_index()

注意:

  • 在您开始日期之后,我只接受了带有 startDate 的行 指定( 2013-09-17 )。
  • target 列的类型均为 int 。我觉得比较自然 因为这些列包含交易的数量, 只是一个整数

最后一件事是将 INDEX_250 的类型更改为 int

df2.INDEX_250 = df2.INDEX_250.astype(int)

INDEX_250 组的结果与您指定的相同,但不包括 2016 2017 中的结果行,这些行不包含在您的 样本数据。

扩展版本-含平均价格

以每个“最终”日期的平均价格扩展结果 和两个目标,都需要进行两次更改。

首先,定义另一个函数以“重新格式化” target DataFrame:

def trgReformat(trg):
    trg = trg[trg.nrTargets_gr_250 > 0].copy()
    trg['avgPrice'] = trg.sm / trg.nrTargets_gr_250
    return trg.drop(columns='sm')

第二,将 targets 函数定义为:

def targets(grp):
    grp['Prd'] = grp.startDate.apply(lambda x: dRng.asof(x) + td30)
    grp.set_index('Prd', inplace=True)
    trg30 = grp.groupby(level=0).agg(
        nrTargets_gr_250=('INDEX_250', 'count'), sm=('priceDeal', 'sum'))\
        .reindex(dRng, fill_value=0)
    trg60 = trg30.rolling(2).sum().fillna(0, downcast='infer')
    trg30 = trgReformat(trg30)
    trg60 = trgReformat(trg60)
    return trg30.join(trg60, how='outer', lsuffix='_30', rsuffix='_60')\
        .fillna(0, downcast='infer').rename_axis('startDate')

此函数使用命名聚合进行计算:

  • nrTargets_gr_250 -行数,
  • sm -价格总和。

原因是 trg60 的计算是使用 rolling (对于 2个连续的30天时段),因此仅 average 是不够的 在这里。

可以在重新格式化时进行平均价格的计算 每个 target 的对象。

此功能的应用与以前一样。