2016-05-11 6 views
3

У меня есть DataFrame некоторых транзакций. Я хочу сгруппировать эти транзакции в отношении значений столбцов item и time: цель состоит в том, чтобы группировать элементы, находящиеся в пределах 1 часа друг от друга. Поэтому мы начинаем новую группу во время следующего наблюдения, которое не было в течение часа после наблюдения (см. Колонку start time в DataFrameB).Как группировать строки в течение периода времени с использованием Python

Вот данные: Я хочу преобразовать A в B.

A= 
item time    result 
A 2016-04-18 13:08:25 Y 
A 2016-04-18 13:57:05 N 
A 2016-04-18 14:00:12 N 
A 2016-04-18 23:45:50 Y 
A 2016-04-20 16:53:48 Y 
A 2016-04-20 17:11:47 N 
B 2016-04-18 15:24:48 N 
C 2016-04-23 13:20:44 N 
C 2016-04-23 14:02:23 Y 


B= 
item start time   end time  Ys Ns total count 
A 2016-04-18 13:08:25 2016-04-18 14:08:25 1 2 3 
A 2016-04-18 23:45:50 2016-04-18 00:45:50 1 0 1 
A 2016-04-20 16:53:48 2016-04-20 17:53:48 1 1 2 
B 2016-04-18 15:24:48 2016-04-18 16:24:48 0 1 1 
C 2016-04-23 13:20:44 2016-04-23 14:20:44 1 1 2 

Вот что я сделал:

grouped = A.groupby('item') 
A['end'] = (grouped['time'].transform(lambda grp: grp.min()+pd.Timedelta(hours=1))) 
A2 = A.loc[(A['time'] <= A['end'])] 

Это дает мне одну группу в день: сделки в течение 1 часа после первой операции. Таким образом, я пропускаю другие транзакции в тот же день, но более чем на 1 час от первого. Моя борьба заключается в том, как получить эти группы. Затем я смогу использовать pd.crosstab, чтобы получить информацию, которую я хочу, из колонки result.

Еще одна идея, которую я имею, заключается в сортировке A по item и time, а затем перейти по строкам. Если время находится в пределах 1 часа от предыдущей строки, оно добавляется к этой группе, в противном случае создается новая группа.

+2

Есть много вопросов, оставшихся без ответа. Как, сгруппированы в течение одного часа, когда? Один час первого наблюдения? Как насчет следующего часа? Началось ли это, когда последний час закончился? Или мы начинаем новый час во время следующего наблюдения, которое не было в течение часа после наблюдения? – piRSquared

+0

что «сгруппировано» в вашем коде? Как ты получил это? – MaxU

+0

@piRSquared Я добавил более подробную информацию к вопросу, чтобы уточнить. – Ana

ответ

1

1) Настройка window_end колонку для последующего использования с .groupby() и определить .get_windows() проверить, для каждой группы item, если row подходит текущее окно тока 1Hr, или ничего не делать и держать инициализирован значение.Применить ко всем item группы:

df['window_end'] = df.time + pd.Timedelta('1H') 

def get_windows(data): 
    window_end = data.iloc[0].window_end 
    for index, row in data.iloc[1:].iterrows(): 
     if window_end > row.time: 
      df.loc[index, 'window_end'] = window_end 
     else: 
      window_end = row.window_end 

df.groupby('item').apply(lambda x: get_windows(x)) 

2) Используйте windows и item с .groupby() и вернуться .value_counts() в transposedDataFrame, очистить index и добавить total:

df = df.groupby(['window_end', 'item']).result.apply(lambda x: x.value_counts().to_frame().T) 
df = df.fillna(0).astype(int).reset_index(level=2, drop=True) 
df['total'] = df.sum(axis=1) 

получить:

      N Y total 
window_end   item    
2016-04-18 14:08:25 A A 2 1  3 
2016-04-18 16:24:48 B B 1 0  1 
2016-04-19 00:45:50 A A 0 1  1 
2016-04-20 17:53:48 A A 1 1  2 
2016-04-23 14:20:44 C C 1 1  2 
+0

Спасибо, да, к сожалению, я не могу использовать Час как мой окунь. – Ana

+0

См. Обновленный ответ. – Stefan

+0

Спасибо, пара комментариев. На втором этапе 'windows' следует заменить на' window_end' и ', правильно? Также вы можете использовать другой для вашего «результата» DataFrame, поэтому он не ошибается в столбец 'result'. – Ana

1

inspi красный (+1) по решению Стефана я пришел к этому:

B = (A.groupby(['item', A.groupby('item')['time'] 
         .diff().fillna(0).dt.total_seconds()//60//60 
       ], 
       as_index=False)['time'].min() 
) 


B[['N','Y']] = (A.groupby(['item', A.groupby('item')['time'] 
            .diff().fillna(0).dt.total_seconds()//60//60 
          ])['result'] 
       .apply(lambda x: x.value_counts().to_frame().T).fillna(0) 
       .reset_index()[['N','Y']] 
) 

Выход:

In [178]: B 
Out[178]: 
    item    time N Y 
0 A 2016-04-18 13:08:25 3.0 1.0 
1 A 2016-04-18 23:45:50 0.0 1.0 
2 A 2016-04-20 16:53:48 0.0 1.0 
3 B 2016-04-18 15:24:48 1.0 0.0 
4 C 2016-04-23 13:20:44 1.0 1.0 

PS идея заключается в том, чтобы использовать A.groupby('item')['time'].diff().fillna(0).dt.total_seconds()//60//60 в составе группировки:

In [179]: A.groupby('item')['time'].diff().fillna(0).dt.total_seconds()//60//60 
Out[179]: 
0  0.0 
1  0.0 
2  0.0 
3  9.0 
4 41.0 
5  0.0 
6  0.0 
7  0.0 
8  0.0 
Name: time, dtype: float64 
+0

Thatnks @MaxU, я получаю 'AttributeError: объект TimedeltaProperties 'не имеет атрибута' total_seconds''. У меня есть 'import datetime как dt'. – Ana

1

Установка

import pandas as pd 
from StringIO import StringIO 

text = """item time    result 
A 2016-04-18 13:08:25 Y 
A 2016-04-18 13:57:05 N 
A 2016-04-18 14:00:12 N 
A 2016-04-18 23:45:50 Y 
A 2016-04-20 16:53:48 Y 
A 2016-04-20 17:11:47 N 
B 2016-04-18 15:24:48 N 
C 2016-04-23 13:20:44 N 
C 2016-04-23 14:02:23 Y 
""" 

df = pd.read_csv(StringIO(text), delimiter="\s{2,}", parse_dates=[1], engine='python') 

So lution

мне нужно создать несколько функций процесса:

def set_time_group(df): 
    cur_time = pd.NaT 
    for index, row in df.iterrows(): 
     if pd.isnull(cur_time): 
      cur_time = row.time 
     delta = row.time - cur_time 
     if delta.seconds/3600. < 1: 
      df.loc[index, 'time_ref'] = cur_time 
     else: 
      df.loc[index, 'time_ref'] = row.time 
      cur_time = row.time 
    return df 

def summarize_results(df): 
    df_ = df.groupby('result').count().iloc[:, 0] 
    df_.loc['total count'] = df_.sum() 
    return df_ 

dfg1 = df.groupby('item').apply(set_time_group) 
dfg2 = dfg1.groupby(['item', 'time_ref']).apply(summarize_results) 
df_f = dfg2.unstack().fillna(0) 

Демонстрация

print df_f 

result      N Y total count 
item time_ref         
A 2016-04-18 13:08:25 2.0 1.0   3.0 
    2016-04-18 23:45:50 0.0 1.0   1.0 
    2016-04-20 16:53:48 1.0 1.0   2.0 
B 2016-04-18 15:24:48 1.0 0.0   1.0 
C 2016-04-23 13:20:44 1.0 1.0   2.0 

 Смежные вопросы

  • Нет связанных вопросов^_^