2016-02-10 2 views
1

У меня есть временной ряд с нерегулярной частотой образцов. Чтобы получить полезные данные из этого, мне нужно найти 10-минутные периоды с приблизительно равномерно распределенными образцами (это я определил среднюю временную шкалу между двумя образцами меньше 20 с).Pandas group время в периоды, начинающиеся в разное время

Пример данных: (Ради этого примера, я сделать его 10s интервалы с средн 2s дельт.)

 
| timestamp    | speed | 
| 2010-01-01 09:20:12 | 10 | 
| 2010-01-01 09:20:14 | 14 | 
| 2010-01-01 09:20:16 | 12 | 
| 2010-01-01 09:20:27 | 18 | 
| 2010-01-01 09:20:28 | 19 | 
| 2010-01-01 09:20:29 | 19 | 

Результат Я надеюсь на это группировка, как следует. Обратите внимание, что вторая группа не включается, потому что образцы сгруппированы вместе в конце периода 10 секунд (27, 28, 29), что означает неявный дополнительный промежуток времени в 7 с, который составляет среднюю дельту 3s.

 
| timestamp    | avg | std | std_over_avg | 
| 2010-01-01 09:20:10 | 12 | 1.63 | 0.136  | 



EDIT: Я думаю, что я комбинируя несколько вещей в моем вопросе (и некоторые неправильно), поэтому я хотел бы исправить/уточнить, что я ищу.

Ссылаясь на данные примера, я хотел бы сгруппировать его в нерегулярные пииворды 10 с; то есть, если есть пробел в данных, следующий 10-й период должен начинаться с отметки времени следующего жизнеспособного rcord. (Пожалуйста, проигнорируйте предыдущее упоминание о равномерно распределенных образцах, оказывается, я неверно истолковал это требование, и я всегда могу отфильтровать его на более позднем этапе, если это необходимо). Так что я хотел бы что-то вроде этого:

 
| period          | count | avg | std | std_over_avg | 
| 2010-01-01 09:20:12 - 2010-01-01 09:20:22 | 3  | 12 | 1.63 | 0.136  | 
| 2010-01-01 09:20:27 - 2010-01-01 09:20:37 | 3  | 18.6 | 0.577| 0.031  | 

ответ

0

я нашел способ достижения большей части того, что я хотел, но это некрасиво и медленно. Надеюсь, кто-то может использовать это в качестве отправной точки для разработки чего-то более полезным:

group_num = 0 
cached_future_time = None 
def group_by_time(df, ind): 
    global group_num 
    global cached_future_time 
    curr_time = ind 
    future_time = ind + datetime.timedelta(minutes=10) 
    # Assume records are sorted chronologically ascending for this to work.  
    end = df.index.get_loc(future_time, method='pad') 
    start = df.index.get_loc(curr_time) 
    num_records = end - start 
    if cached_future_time is not None and curr_time < cached_future_time: 
     pass 
    elif cached_future_time is not None and curr_time >= cached_future_time: 
     group_num += 1 
     # Only increase the cached_future_time mark if we have sufficient data points to make this group useful. 
     if num_records >= 30: 
      cached_future_time = future_time 
    elif cached_future_time is None: 
     cached_future_time = future_time 
    return group_num 

grp = df.groupby(lambda x: group_by_time(df, x)) 

Edit:

Ok я нашел гораздо больше панды-Ic способ сделать это, которое также значительно быстрее, чем уродливый цикл выше. Мое падение в вышеприведенном ответе состояло в том, что мне нужно было выполнить большую часть работы по вычислению групп в функции groupby (и считая, что метод не применялся во всех рядах разумно).

# Add 10min to our timestamp and shift the values in that column 30 records 
# into the future. We can then find all the timestamps that are 30 records 
# newer but still within 10min of the original timestamp (ensuring that we have a 10min group with 
# at least 30 records). 
records["future"] = records["timestamp"] + datetime.timedelta(minutes=10) 
starts = list(records[(records["timestamp"] <= records.future.shift(30)) & records.group_num.isnull()].index) 

group_num = 1 
# For each of those starting timestamps, grab a slice up to 10min in the future 
# and apply a group number. 
for start in starts: 
    group = records.loc[start:start + datetime.timedelta(minutes=10), 'group_num'] 
    if len(group[group.isnull()]) >= 30: 
     # Only apply group_num to null values so that we get disjoint groups (no overlaps). 
     group[group.isnull()] = group_num 
     group_num += 1 
Смежные вопросы