2014-11-21 25 views
11

Giả sử tôi có dưới khung dữ liệugấu trúc lăn tổng lăm phút cuối

Date, A 
2014-11-21 11:00:00, 1 
2014-11-21 11:03:00, 4 
2014-11-21 11:04:00, 1 
2014-11-21 11:05:00, 2 
2014-11-21 11:07:00, 4 
2014-11-21 11:08:00, 1 
2014-11-21 11:12:00, 1 
2014-11-21 11:13:00, 2 

cột đầu tiên là đối tượng datetime và cột thứ hai là một số nguyên. Những gì tôi muốn là để tính tổng của cột 'A' cho năm phút cuối cùng cho mỗi hàng.

Ví dụ cho hàng 2014-11-21 11:12:00, 1, tổng của cột 'A' sẽ là 2 (1 + 1) và tổng của cột 'A' cho hàng 2014-11-21 11:05:00, 2 sẽ là 7 (2 + 1 + 4). Điều quan trọng là số lượng các hàng trong quá khứ cho cửa sổ thời gian (5 phút) không giống nhau đối với mỗi hàng (Do chuỗi thời gian là bất thường).

Làm cách nào tôi có thể nhận được tổng của năm phút cuối cùng cho cột 'A' bằng cách sử dụng phương pháp rolling_sum trong gấu trúc? Cảm ơn trước.

Trả lời

13

Nói chung, nếu ngày là hoàn toàn tùy ý, tôi nghĩ bạn sẽ buộc phải sử dụng một Python for-loop qua các hàng hoặc use df.apply, (mà dưới mui xe, cũng sử dụng một vòng lặp Python.)

Tuy nhiên, nếu Ngày của bạn chia sẻ tần suất chung, như trường hợp trên, thì có một mẹo cần nhanh hơn nhiều so với sử dụng df.apply: Mở rộng bộ đếm thời gian theo tần suất chung - trong trường hợp này, 1 phút - điền vào các NaN với số không, và sau đó gọi rolling_sum:

In [279]: pd.rolling_sum(df.set_index(['Date']).asfreq('1T').fillna(0), window=5, min_periods=1).reindex(df['Date']) 
Out[279]: 
         A 
Date     
2014-11-21 11:00:00 1 
2014-11-21 11:03:00 5 
2014-11-21 11:04:00 6 
2014-11-21 11:05:00 7 
2014-11-21 11:07:00 11 
2014-11-21 11:08:00 8 
2014-11-21 11:12:00 2 
2014-11-21 11:13:00 3 

Tất nhiên, bất kỳ chuỗi thời gian nào có tần suất chung nếu bạn sẵn sàng chấp nhận mức độ chi tiết đủ nhỏ, nhưng kích thước yêu cầu của df.asfreq(...) có thể làm cho mẹo này không thực tế.


Dưới đây là ví dụ về cách tiếp cận tổng quát hơn sử dụng df.apply. Lưu ý rằng việc gọi số searchsorted phụ thuộc vào số df['Date'] đang được sắp xếp.

import numpy as np 
import pandas as pd 
df = pd.read_csv('data', parse_dates=[0], sep=',\s*') 
start_dates = df['Date'] - pd.Timedelta(minutes=5) 
df['start_index'] = df['Date'].values.searchsorted(start_dates, side='right') 
df['end_index'] = np.arange(len(df)) 

def sum_window(row): 
    return df['A'].iloc[row['start_index']:row['end_index']+1].sum() 
df['rolling_sum'] = df.apply(sum_window, axis=1) 

print(df[['Date', 'A', 'rolling_sum']]) 

mang

    Date A rolling_sum 
0 2014-11-21 11:00:00 1   1 
1 2014-11-21 11:03:00 4   5 
2 2014-11-21 11:04:00 1   6 
3 2014-11-21 11:05:00 2   7 
4 2014-11-21 11:07:00 4   11 
5 2014-11-21 11:08:00 1   8 
6 2014-11-21 11:12:00 1   2 
7 2014-11-21 11:13:00 2   3 

Dưới đây là một chuẩn mực so sánh các trick df.asfreq so với gọi df.apply:

import numpy as np 
import pandas as pd 
df = pd.read_csv('data', parse_dates=[0], sep=',\s*') 

def big_df(df): 
    df = df.copy() 
    for i in range(7): 
     dates = df['Date'] + pd.Timedelta(df.iloc[-1]['Date']-df.iloc[0]['Date']) + pd.Timedelta('1 minute') 
     df2 = pd.DataFrame({'Date': dates, 'A': df['A']}) 
     df = pd.concat([df, df2]) 
    df = df.reset_index(drop=True) 
    return df 

def using_apply(): 
    start_dates = df['Date'] - pd.Timedelta(minutes=5) 
    df['start_index'] = df['Date'].values.searchsorted(start_dates, side='right') 
    df['end_index'] = np.arange(len(df)) 

    def sum_window(row): 
     return df['A'].iloc[row['start_index']:row['end_index']+1].sum() 

    df['rolling_sum'] = df.apply(sum_window, axis=1) 
    return df[['Date', 'rolling_sum']] 

def using_asfreq(): 
    result = (pd.rolling_sum(
     df.set_index(['Date']).asfreq('1T').fillna(0), 
     window=5, min_periods=1).reindex(df['Date'])) 
    return result 

In [364]: df = big_df(df) 

In [367]: %timeit using_asfreq() 
1000 loops, best of 3: 1.21 ms per loop 

In [368]: %timeit using_apply() 
1 loops, best of 3: 208 ms per loop 
+0

Cảm ơn bạn rất nhiều vì câu trả lời nhanh. Tôi không thể sử dụng phương thức df.asfreq (...) vì độ chi tiết nhỏ nhất trong tập dữ liệu của tôi là giây và tôi có hàng triệu hàng. Nhưng phương pháp df.apply thực hiện thủ thuật. –

+0

Cách tiếp cận chung hoạt động, chỉ một điều cần lưu ý nếu nó được sử dụng trong mã dài: hàm 'sum_window' không sử dụng đầu vào' df' như một cách rõ ràng vì vậy cần phải cẩn thận. – nilesh

Các vấn đề liên quan