Python 如何将不同长度的时间窗口应用于数据帧

Python 如何将不同长度的时间窗口应用于数据帧,python,pandas,numpy,dataframe,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

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

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
我想看看从第一笔销售交易到2013-09-17的前30天和60天,每个(按索引250分组)发生了多少笔销售交易。示例数据集仅用于一个
索引_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
我注意到您希望将startDate更改为相应的 30天期限,从您的开始日期开始

另一个细节是,您希望结果按索引\u 250分组- 之前(两个时期内)有多少笔交易与 索引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')
应用它并重置索引(仅按此顺序,以获得正确的列顺序):

注:

  • 我只在您选择的开始日期当天或之后选择startDate的行 规定(2013-09-17)
  • 两个目标列的类型都是int。我认为它更自然, 因为这些列包含交易的数量,本质上 只是一个整数
最后一件事是将索引类型_250更改为int:

索引_250组的结果与您指定的一样,不包括 2016年和2017年的结果行,未包含在您的 样本数据

扩展版-平均价格 通过每个“最终”日期的平均价格扩展结果 两个目标都需要两个改变

首先,定义另一个函数来“重新格式化”目标数据帧:

def trgReformat(trg):
    trg = trg[trg.nrTargets_gr_250 > 0].copy()
    trg['avgPrice'] = trg.sm / trg.nrTargets_gr_250
    return trg.drop(columns='sm')
其次,将目标函数定义为:

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')
此函数使用命名聚合来计算:

  • NRU gr_250-行数
  • sm-价格之和
原因是trg60的计算是使用滚动(用于 2个连续的30天周期),因此仅凭平均值是不够的 在这里

平均价格的计算可以在重新格式化时进行 每一个目标


此函数的应用与以前一样。

您能提供两个索引的数据吗?@QuangHoang我做了一个编辑。非常感谢,它可以工作,我如何更改它,使每个时间窗口都能计算过去30天和60天的平均
priceDeal
def trgReformat(trg):
    trg = trg[trg.nrTargets_gr_250 > 0].copy()
    trg['avgPrice'] = trg.sm / trg.nrTargets_gr_250
    return trg.drop(columns='sm')
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')