как применить временные окна разной длины к пандамскому фрейму - PullRequest
2 голосов
/ 12 октября 2019

У меня есть следующий фрейм данных, каждая строка представляет транзакцию продажи:

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 Ответ

1 голос
/ 13 октября 2019

Я заметил, что вы хотите, чтобы startDate был изменен до конца соответствующего 30-дневного периода, начиная с вашей даты начала.

Другая деталь заключается в том, что вам нужен результат сгруппировано по INDEX_250 - сколько предыдущих транзакций (в обоих соответствующих периодах) было с одинаковым значением INDEX_250 .

ПримечаниеКроме того, скользящие вычисления могут выполняться в окне, содержащем строки из числа будущих периодов, тогда как вы хотите количество транзакций за предыдущих 30 или 60 днейи Rolling не допускает отрицательного числа периодов.

Вот почему я выбрал иной подход, чем "обычный" Rolling .

Начать свспомогательные переменные:

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()

Примечаниеs:

  • Я взял только строки с 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')

Secondопределить цели функцию как:

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 - количество строк,
  • см - сумма цен.

Причина в том, чтовычисление trg60 выполняется с использованием скользящего (для 2 последовательных 30-дневных периодов), поэтому одного среднего здесь будет недостаточно.

Вычисление средней цены может быть выполнено так же поздно, как и при переформатировании каждой цели .

Применение этой функции такое же, как и раньше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...