Как разделить индекс временных рядов на основе непрерывности

#python #pandas

#python #pandas

Вопрос:

Итак, у меня есть ряд дат, и я хочу разделить его на куски на основе непрерывности.Ряд выглядит следующим образом:

 2019-01-01    36.581647
2019-01-02    35.988585
2019-01-03    35.781111
2019-01-04    35.126273
2019-01-05    34.401451
2019-01-06    34.351714
2019-01-07    34.175517
2019-01-08    33.622116
2019-01-09    32.861861
2019-01-10    32.915251
2019-01-11    32.866832
2019-01-12    32.214259
2019-01-13    31.707626
2019-01-14    32.556175
2019-01-15    32.674965
2019-01-16    32.391766
2019-01-17    32.463836
2019-01-18    32.151290
2019-01-19    31.952946
2019-01-20    31.739855
2019-01-21    31.355354
2019-01-22    31.271243
2019-01-23    31.273255
2019-01-24    31.442803
2019-01-25    32.034161
2019-01-26    31.455956
2019-01-27    31.408881
2019-01-28    31.066477
2019-01-29    30.489070
2019-01-30    30.356210
2019-01-31    30.470496
2019-02-01    29.949312
2019-02-02    29.916971
2019-02-03    29.865447
2019-02-04    29.512595
2019-02-05    29.297967
2019-02-06    28.743329
2019-02-07    28.509800
2019-02-08    27.681294
2019-02-10    26.441899
2019-02-11    26.787360
2019-02-12    27.368621
2019-02-13    27.085167
2019-02-14    26.856398
2019-02-15    26.793370
2019-02-16    26.334788
2019-02-17    25.906381
2019-02-18    25.367705
2019-02-19    24.939880
2019-02-20    25.021575
2019-02-21    25.006527
2019-02-22    24.984512
2019-02-23    24.372664
2019-02-24    24.183728
2019-10-10    23.970567
2019-10-11    24.755944
2019-10-12    25.155136
2019-10-13    25.273033
2019-10-14    25.490775
2019-10-15    25.864637
2019-10-16    26.168158
2019-10-17    26.600422
2019-10-18    26.959990
2019-10-19    26.965104
2019-10-20    27.128877
2019-10-21    26.908657
2019-10-22    26.979930
2019-10-23    26.816817
2019-10-24    27.058753
2019-10-25    27.453882
2019-10-26    27.358057
2019-10-27    27.374445
2019-10-28    27.418648
2019-10-29    27.458521
2019-10-30    27.859687
2019-10-31    28.093942
2019-11-01    28.494706
2019-11-02    28.517255
2019-11-03    28.492476
2019-11-04    28.723757
2019-11-05    28.835151
2019-11-06    29.367227
2019-11-07    29.920598
2019-11-08    29.746370
2019-11-09    29.498023
2019-11-10    29.745044
2019-11-11    30.935084
2019-11-12    31.710737
2019-11-13    32.890792
2019-11-14    33.011911
2019-11-15    33.121803
2019-11-16    32.805403
2019-11-17    32.887447
2019-11-18    33.350492
2019-11-19    33.525344
2019-11-20    33.791458
2019-11-21    33.674697
2019-11-22    33.642584
2019-11-23    33.704386
2019-11-24    33.472346
2019-11-25    33.317035
2019-11-26    32.934307
2019-11-27    33.573193
2019-11-28    32.840514
2019-11-29    33.085686
2019-11-30    33.138131
2019-12-01    33.344264
2019-12-02    33.524948
2019-12-03    33.694687
2019-12-04    33.836534
2019-12-05    34.343416
2019-12-06    34.321793
2019-12-07    34.156796
2019-12-08    34.399591
2019-12-09    34.931185
2019-12-10    35.294034
2019-12-11    35.021331
2019-12-12    34.292483
2019-12-13    34.330898
2019-12-14    34.354278
2019-12-15    34.436500
2019-12-16    34.869841
2019-12-17    34.932567
2019-12-18    34.855816
2019-12-19    35.226241
2019-12-20    35.184222
2019-12-21    35.456716
2019-12-22    35.730350
2019-12-23    35.739911
2019-12-24    35.800030
2019-12-25    35.896615
2019-12-26    35.871280
2019-12-27    35.509646
2019-12-28    35.235416
2019-12-29    34.848605
2019-12-30    34.926700
2019-12-31    34.787211
  

И я хочу разделить его следующим образом:

 chunk,start,end,value
0,2019-01-01,2019-02-24,35.235416
1,2019-10-10,2019-12-31,34.787211
  

Значения являются случайными и могут относиться к любой агрегированной функции. Об этом мне плевать. Но все еще не могу найти способ сделать это. Важно то, какие фрагменты я получаю

Комментарии:

1. вы переходите с 2019-02-08 на 2019-02-10 почему это не представлено в вашем ожидаемом выводе?

2. Упс, я этого не заметил. Но, конечно, я хочу, чтобы это было включено

Ответ №1:

Я предполагаю, что ваш фрейм данных:

  • имеет столбцы с именами Дата и сумма,
  • Столбец даты имеет тип datetime (не строка).

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

 def grpRes(grp):
    return pd.Series([grp.Date.min(), grp.Date.max(), grp.Amount.mean()],
        index=['start', 'end', 'value'])
  

Затем примените это к каждой группе и переименуйте индекс:

 res = df.groupby(df.Date.diff().dt.days.fillna(1, downcast='infer')
    .gt(1).cumsum()).apply(grpRes)
res.index.name = 'chunk'
  

Я заметил, что в вашем примере данных нет строки для 2019-02-09, но вы
не рассматривайте такой единственный пропущенный день как нарушение
«правило непрерывности».

Если вы действительно хотите такого поведения, измените gt(1), например, на gt(2),,,.

Комментарии:

1. Это работает безупречно и легко настраивается для включения порога непрерывности!

Ответ №2:

Одним из способов является логическое индексирование, которое предполагает, что ваши данные уже отсортированы. Я также предположил, что ваши столбцы были названы ['Date', 'Val]

 #reset index so you have a dataframe
data = s.reset_index()
# boolean indexing where the date below is greater than 1 day
end = data[((data['Date'] - data['Date'].shift(-1)).dt.days.abs() != 1)].reset_index(drop=True).rename(columns={'Date':'End', 'Val': 'End_val'})
# boolean indexing where the date above is greater than one day
start = data[(data['Date'] - data['Date'].shift()).dt.days != 1].reset_index(drop=True).rename(columns={'Date':'Start', 'Val':'Start_val'})
# concat your data
pd.concat([start,end], axis=1)

       Start  Start_val        End    End_val
0 2019-01-01  36.581647 2019-02-08  27.681294
1 2019-02-10  26.441899 2019-02-24  24.183728
2 2019-10-10  23.970567 2019-12-31  34.787211