2016-02-06 15 views
9

Tôi có một khung dữ liệu gấu trúc với các ngày cách nhau không đều. Có cách nào để sử dụng 7 ngày như một cửa sổ di chuyển để tính toán median absolute deviation, trung bình, v.v.? Tôi cảm thấy như tôi bằng cách nào đó có thể sử dụng pandas.rolling_apply nhưng nó không mất ngày khoảng cách bất thường cho tham số cửa sổ. Tôi tìm thấy một bài viết tương tự https://stackoverflow.com/a/30244019/3128336 và đang cố gắng để tạo ra chức năng tùy chỉnh của tôi nhưng vẫn không thể tìm ra .. Bất cứ ai có thể giúp đỡ?Cách sử dụng ngày làm cửa sổ cho gấu trúc rolling_apply chức năng

import pandas as pd 
from datetime import datetime 

person = ['A','B','C','B','A','C','A','B','C','A',] 
ts = [ 
    datetime(2000, 1, 1), 
    datetime(2000, 1, 1), 
    datetime(2000, 1, 10), 
    datetime(2000, 1, 20), 
    datetime(2000, 1, 25), 
    datetime(2000, 1, 30), 
    datetime(2000, 2, 8), 
    datetime(2000, 2, 12), 
    datetime(2000, 2, 17), 
    datetime(2000, 2, 20), 
] 
score = [9,2,1,3,8,4,2,3,1,9] 
df = pd.DataFrame({'ts': ts, 'person': person, 'score': score}) 

df trông như thế này

person score ts 
0 A  9  2000-01-01 
1 B  2  2000-01-01 
2 C  1  2000-01-10 
3 B  3  2000-01-20 
4 A  8  2000-01-25 
5 C  4  2000-01-30 
6 A  2  2000-02-08 
7 B  3  2000-02-12 
8 C  1  2000-02-17 
9 A  9  2000-02-20 
+0

Bạn có muốn một cửa sổ di chuyển hoặc một cửa sổ mở rộng? – Goyo

+0

Tôi muốn di chuyển cửa sổ. Vì vậy, một cái gì đó như thế này 'pd.rolling_apply (df, window = relativedelta (ngày = 7), func, min_periods = 1)' Tôi đã nhầm lẫn giữa hai. Hãy để tôi sửa bài viết của tôi. Cảm ơn bạn đã chỉ ra –

+0

Bạn có thể giải thích những gì không phù hợp với giải pháp cho câu hỏi bạn đã liên kết không? Tôi cho rằng việc lấy lại dữ liệu của bạn cho dữ liệu hàng ngày trước khi áp dụng tính năng lăn sẽ loại bỏ các ngày trùng lặp? – joris

Trả lời

5

Bạn có thể sử dụng một đồng bằng thời gian để chọn hàng trong cửa sổ của bạn và sau đó sử dụng áp dụng đối với chạy qua mỗi hàng và tổng hợp:

>>> from datetime import timedelta 
>>> delta = timedelta(days=7) 
>>> df_score_mean = df.apply(lambda x: np.mean(df['score'][df['ts'] <= x['ts'] + delta]), axis=1) 
0 5.500000 
1 5.500000 
2 4.000000 
3 4.600000 
4 4.500000 
5 4.500000 
6 4.555556 
7 4.200000 
8 4.200000 
9 4.200000 
+0

Điều này gần với những gì tôi cần! Chỉ cần một câu hỏi ở đây, làm thế nào có thể thay đổi cách thay đổi hoạt động với áp dụng? Hàm lambda mà bạn đề xuất hoạt động theo cách ngược lại. Ví dụ, 'pd.rolling_median (df.score, window = 2)' trả về NA cho hàng đầu tiên, không phải hàng cuối cùng. (Tôi thực sự muốn thêm một tính năng tương đương với 'min_periods = 1' để sao chép các giá trị cho tuần đầu tiên) –

+1

Tôi tin rằng hàm lambda không trả về NA cho bất kỳ hàng nào vì nó sẽ luôn chọn ít nhất một hàng để thực hiện chức năng np.mean() trên. Bạn đang hỏi làm thế nào để thay đổi cửa sổ để có thể chuyển tiếp tìm kiếm hoặc nhìn lại? Trong hàm lambda, chúng tôi chọn bất kỳ hàng nào nhỏ hơn hoặc bằng hàng hiện tại + 7 ngày. Nếu bạn muốn nhìn lại 7 ngày, bạn có thể chọn các hàng lớn hơn hoặc bằng hàng hiện tại - 7 ngày. –

+0

Ah có ý nghĩa! Có, tôi cần nhìn lại. –

0

tôi không đủ quen thuộc với các chức năng ngày lăn - vì vậy tôi tự hỏi về việc thêm dữ liệu còn thiếu (trên thực tế là một Dataframe đầy dữ liệu bị thiếu) Và sau đó cửa sổ cuộn của bạn nên dễ thực hiện hơn.

from datetime import date 
import pandas as pd 
##############Your Initial DataFrame ############## 
person = ['A','B','C','B','A','C','A','B','C','A',] 
ts = [ 
    datetime(2000, 1, 1), 
    datetime(2000, 1, 1), 
    datetime(2000, 1, 10), 
    datetime(2000, 1, 20), 
    datetime(2000, 1, 25), 
    datetime(2000, 1, 30), 
    datetime(2000, 2, 8), 
    datetime(2000, 2, 12), 
    datetime(2000, 2, 17), 
    datetime(2000, 2, 15), 
] 
score = [9,2,1,3,8,4,2,3,1,9] 
df = pd.DataFrame({'ts': ts, 'person': person, 'score': score}) 
################## Blank DataFrame in Same Format ############### 
#Create some dates 
start = date(2000,1,1) 
end = date(2000,3,1) 
#We have 3 people 
Eperson=['A','B','C'] 
#They Score 0 
Escore=[0] 
#Need a date range in Days 
ets=pd.date_range(start, end, freq='D') 
dfEmpty=pd.DataFrame([(c,b,0) for b in Eperson for c in ets]) 
dfEmpty.columns=['ts','person','score'] 

################# Now Join them 

dfJoin=dfEmpty.merge(df,how='outer',on=['ts','person']) 
dfJoin['score']=dfJoin.score_x+dfJoin.score_y 
dfJoin.score.fillna(0,inplace=True) 
del dfJoin['score_x'] 
del dfJoin['score_y']' 

Bây giờ bạn có khung dữ liệu sẽ không có ngày mất tích mỗi người - và nếu ngày đầu tiên đã mất tích sau đó người/điểm sẽ là 0.

Tôi đánh giá cao điều này có thể không làm việc, bạn nên được xử lý với hàng triệu bản ghi.

Xin lỗi cho các nhận xét loại không PEP ... nó vẫn đang hoạt động.

0

Chỉ cần đăng giải pháp của tôi dựa trên số suggestion của Brian Huey.

from datetime import datetime, timedelta 
import statsmodels.api as sm 

delta = timedelta(days=7) 

def calc_mad_mean(row): 
    start = row['ts'] 
    end = start + delta 
    subset = df['score'][(start <= df['ts']) & (df['ts'] < end)] 
    return pd.Series({'mad': sm.robust.mad(subset), 'med': np.median(subset)}) 

first_wk = df.ts.iloc[0] + delta 
results = df[first_wk < df.ts].apply(calc_mad_mean, axis=1) 
df.join(results, how='outer') 

Kết quả

person score ts   mad  med 
0 A  9  2000-01-01 NaN  NaN 
1 B  2  2000-01-01 NaN  NaN 
2 C  1  2000-01-10 0.000000 1.0 
3 B  3  2000-01-20 3.706506 5.5 
4 A  8  2000-01-25 2.965204 6.0 
5 C  4  2000-01-30 0.000000 4.0 
6 A  2  2000-02-08 0.741301 2.5 
7 B  3  2000-02-12 1.482602 2.0 
8 C  1  2000-02-17 5.930409 5.0 
9 A  9  2000-02-20 0.000000 9.0 
Các vấn đề liên quan