Подтвердить что ты не робот

Как создать идентификатор группы на основе 5-минутного интервала в pandas timeseries?

У меня есть временный фреймворк данных df выглядит так (время seris происходит в тот же день, но через разные часы:

                                id               val 
 time                    
2014-04-03 16:01:53             23              14389      
2014-04-03 16:01:54             28              14391             
2014-04-03 16:05:55             24              14393             
2014-04-03 16:06:25             23              14395             
2014-04-03 16:07:01             23              14395             
2014-04-03 16:10:09             23              14395             
2014-04-03 16:10:23             26              14397             
2014-04-03 16:10:57             26              14397             
2014-04-03 16:11:10             26              14397              

Мне нужно создать группу каждые 5 минут, начиная с 16:00:00. Это все строки с диапазоном от 16:00:00 до 16:05:00, его значение нового столбца period равно 1. (количество строк внутри каждой группы нерегулярно, поэтому я не могу просто отрезать группу)

В конце концов, данные должны выглядеть так:

                                id               val           period 
time            
2014-04-03 16:01:53             23              14389             1
2014-04-03 16:01:54             28              14391             1
2014-04-03 16:05:55             24              14393             2
2014-04-03 16:06:25             23              14395             2
2014-04-03 16:07:01             23              14395             2
2014-04-03 16:10:09             23              14395             3
2014-04-03 16:10:23             26              14397             3
2014-04-03 16:10:57             26              14397             3
2014-04-03 16:11:10             26              14397             3

Цель состоит в выполнении некоторой операции groupby, но операция, которую мне нужно сделать, не включена в метод pd.resample(how=' '). Поэтому я должен создать столбец period, чтобы идентифицировать каждую группу, а затем сделать df.groupby('period').apply(myfunc).

Любая помощь или комментарии высоко оценены.

Спасибо!

4b9b3361

Ответ 1

Вы можете использовать функцию TimeGrouper в groupy/apply. С помощью TimeGrouper вам не нужно создавать столбец периода. Я знаю, что вы не пытаетесь вычислить среднее значение, но я буду использовать его в качестве примера:

>>> df.groupby(pd.TimeGrouper('5Min'))['val'].mean()

time
2014-04-03 16:00:00    14390.000000
2014-04-03 16:05:00    14394.333333
2014-04-03 16:10:00    14396.500000

Или пример с явным apply:

>>> df.groupby(pd.TimeGrouper('5Min'))['val'].apply(lambda x: len(x) > 3)

time
2014-04-03 16:00:00    False
2014-04-03 16:05:00    False
2014-04-03 16:10:00     True

Doctstring для TimeGrouper:

Docstring for resample:class [email protected]

TimeGrouper(self, freq = 'Min', closed = None, label = None,
how = 'mean', nperiods = None, axis = 0, fill_method = None,
limit = None, loffset = None, kind = None, convention = None, base = 0,
**kwargs)

Custom groupby class for time-interval grouping

Parameters
----------
freq : pandas date offset or offset alias for identifying bin edges
closed : closed end of interval; left or right
label : interval boundary to use for labeling; left or right
nperiods : optional, integer
convention : {'start', 'end', 'e', 's'}
    If axis is PeriodIndex

Notes
-----
Use begin, end, nperiods to generate intervals that cannot be derived
directly from the associated object

Edit

Я не знаю об элегантном способе создания столбца периода, но будет работать следующее:

>>> new = df.groupby(pd.TimeGrouper('5Min'),as_index=False).apply(lambda x: x['val'])
>>> df['period'] = new.index.get_level_values(0)
>>> df

                     id    val  period
time
2014-04-03 16:01:53  23  14389       0
2014-04-03 16:01:54  28  14391       0 
2014-04-03 16:05:55  24  14393       1
2014-04-03 16:06:25  23  14395       1
2014-04-03 16:07:01  23  14395       1
2014-04-03 16:10:09  23  14395       2
2014-04-03 16:10:23  26  14397       2
2014-04-03 16:10:57  26  14397       2
2014-04-03 16:11:10  26  14397       2

Это работает, потому что groupby здесь с as_index = False фактически возвращает столбцы периода, которые вы хотите как часть мультииндекса, и я просто захвачу эту часть мультииндекса и присваиваю новый столбец в исходном фрейме данных. Вы можете сделать что-нибудь в приложении, я просто хочу индекс:

>>> new

   time
0  2014-04-03 16:01:53    14389
   2014-04-03 16:01:54    14391
1  2014-04-03 16:05:55    14393
   2014-04-03 16:06:25    14395
   2014-04-03 16:07:01    14395
2  2014-04-03 16:10:09    14395
   2014-04-03 16:10:23    14397
   2014-04-03 16:10:57    14397
   2014-04-03 16:11:10    14397

>>>  new.index.get_level_values(0)

Int64Index([0, 0, 1, 1, 1, 2, 2, 2, 2], dtype='int64')

Ответ 2

В зависимости от того, что вы делаете, если я правильно понимаю вопрос, можно сделать намного проще, просто используя метод resample

#Get some data
index = pd.DatetimeIndex(start='2013-01-01 00:00', end='2013-01-31 00:00', freq='min')
a = np.random.randint(20, high=30, size=(len(index),1))
b = np.random.randint(14440, high=14449, size=(len(index),1))
df = pd.DataFrame(np.concatenate((a,b), axis=1), index=index, columns=['id','val'])
df.head()


Out[34]:
                     id  val
2013-01-01 00:00:00  20  14446
2013-01-01 00:01:00  25  14443
2013-01-01 00:02:00  25  14448
2013-01-01 00:03:00  20  14445
2013-01-01 00:04:00  28  14442

#Define function for variance
import numpy as np
def pyfun(X):

    if X.shape[0] <= 1:
        result = nan

    else:    
        total = 0
        for x in X:
            total = total + x
        mean = float(total) / X.shape[0]

        total = 0
        for x in X:
            total = total + (mean-x)**2
        result = float(total) / (X.shape[0]-1)

    return result

#Try it out
df.resample('5min', how=pyfun)


Out[53]:
                     id val
2013-01-01 00:00:00  12.3    5.7
2013-01-01 00:05:00  9.3     7.3
2013-01-01 00:10:00  4.7     0.8
2013-01-01 00:15:00  10.8    10.3
2013-01-01 00:20:00  11.5    1.5

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

df.resample('5min', how=np.var).head()


Out[54]:
                     id val
2013-01-01 00:00:00  12.3    5.7
2013-01-01 00:05:00  9.3     7.3
2013-01-01 00:10:00  4.7     0.8
2013-01-01 00:15:00  10.8    10.3
2013-01-01 00:20:00  11.5    1.5