2012-11-01 26 views
6

Tôi có một DataFrame bao gồm nhiều chuỗi thời gian xếp chồng. Chỉ số là (poolId, tháng) trong đó cả hai là số nguyên, "tháng" là số tháng kể từ năm 2000. Cách tốt nhất để tính các phiên bản một tháng bị trễ của nhiều biến là gì?Cách hiệu quả nhất để thay đổi chuỗi thời gian MultiIndex

Ngay bây giờ, tôi làm điều gì đó như:

cols_to_shift = ["bal", ...5 more columns...] 
df_shift = df[cols_to_shift].groupby(level=0).transform(lambda x: x.shift(-1)) 

Đối với dữ liệu của tôi, điều này đã cho tôi một đầy đủ 60 s để chạy. (Tôi có 48k hồ khác nhau và có tổng cộng 718k hàng.)

tôi là chuyển đổi này từ mã R và cuộc gọi data.table tương đương:

dt.shift <- dt[, list(bal=myshift(bal), ...), by=list(poolId)] 

chỉ mất 9 s để chạy. (Ở đây "myshift" là một cái gì đó giống như "chức năng (x) c (x [-1], NA)".)

Có cách nào tôi có thể đưa chú gấu trúc trở lại tốc độ không? Tôi đã thử nghiệm điều này trên 0.8.1.

Edit: Đây là một ví dụ về việc tạo ra một tập dữ liệu gần đủ, vì vậy bạn có thể nhận được một số ý tưởng về những gì tôi có nghĩa là:

ids = np.arange(48000) 
lens = np.maximum(np.round(15+9.5*np.random.randn(48000)), 1.0).astype(int) 
id_vec = np.repeat(ids, lens) 
lens_shift = np.concatenate(([0], lens[:-1])) 
mon_vec = np.arange(lens.sum()) - np.repeat(np.cumsum(lens_shift), lens) 
n = len(mon_vec) 
df = pd.DataFrame.from_items([('pool', id_vec), ('month', mon_vec)] + [(c, np.random.rand(n)) for c in 'abcde']) 
df = df.set_index(['pool', 'month']) 
%time df_shift = df.groupby(level=0).transform(lambda x: x.shift(-1)) 

Đó mất 64 s khi tôi thử nó. Dữ liệu này có mọi chuỗi bắt đầu từ tháng 0; thực sự, tất cả chúng sẽ kết thúc vào tháng np.max (ống kính), với ngày bắt đầu bị rách nát, nhưng đủ tốt.

Chỉnh sửa 2: Dưới đây là một số mã so sánh R. Điều này mất 0.8 s. Yếu tố 80, không tốt.

library(data.table) 
ids <- 1:48000 
lens <- as.integer(pmax(1, round(rnorm(ids, mean=15, sd=9.5)))) 
id.vec <- rep(ids, times=lens) 
lens.shift <- c(0, lens[-length(lens)]) 
mon.vec <- (1:sum(lens)) - rep(cumsum(lens.shift), times=lens) 
n <- length(id.vec) 
dt <- data.table(pool=id.vec, month=mon.vec, a=rnorm(n), b=rnorm(n), c=rnorm(n), d=rnorm(n), e=rnorm(n)) 
setkey(dt, pool, month) 
myshift <- function(x) c(x[-1], NA) 
system.time(dt.shift <- dt[, list(month=month, a=myshift(a), b=myshift(b), c=myshift(c), d=myshift(d), e=myshift(e)), by=pool]) 
+0

Tôi mở một vấn đề GitHub ở đây: https://github.com/pydata/pandas/issue/2162. Tôi sẽ xem xét –

Trả lời

6

tôi sẽ đề nghị bạn định hình lại các dữ liệu và làm một sự thay đổi duy nhất so với các phương pháp groupby:

result = df.unstack(0).shift(1).stack() 

này chuyển thứ tự của các cấp, do đó bạn muốn để trao đổi và sắp xếp lại:

result = result.swaplevel(0, 1).sortlevel(0) 

bạn có thể xác minh nó được tụt bởi một dấu chấm (bạn muốn thay đổi (1) thay vì thay đổi (-1)):

In [17]: result.ix[1] 
Out[17]: 
       a   b   c   d   e 
month             
1  0.752511 0.600825 0.328796 0.852869 0.306379 
2  0.251120 0.871167 0.977606 0.509303 0.809407 
3  0.198327 0.587066 0.778885 0.565666 0.172045 
4  0.298184 0.853896 0.164485 0.169562 0.923817 
5  0.703668 0.852304 0.030534 0.415467 0.663602 
6  0.851866 0.629567 0.918303 0.205008 0.970033 
7  0.758121 0.066677 0.433014 0.005454 0.338596 
8  0.561382 0.968078 0.586736 0.817569 0.842106 
9  0.246986 0.829720 0.522371 0.854840 0.887886 
10  0.709550 0.591733 0.919168 0.568988 0.849380 
11  0.997787 0.084709 0.664845 0.808106 0.872628 
12  0.008661 0.449826 0.841896 0.307360 0.092581 
13  0.727409 0.791167 0.518371 0.691875 0.095718 
14  0.928342 0.247725 0.754204 0.468484 0.663773 
15  0.934902 0.692837 0.367644 0.061359 0.381885 
16  0.828492 0.026166 0.050765 0.524551 0.296122 
17  0.589907 0.775721 0.061765 0.033213 0.793401 
18  0.532189 0.678184 0.747391 0.199283 0.349949 

In [18]: df.ix[1] 
Out[18]: 
       a   b   c   d   e 
month             
0  0.752511 0.600825 0.328796 0.852869 0.306379 
1  0.251120 0.871167 0.977606 0.509303 0.809407 
2  0.198327 0.587066 0.778885 0.565666 0.172045 
3  0.298184 0.853896 0.164485 0.169562 0.923817 
4  0.703668 0.852304 0.030534 0.415467 0.663602 
5  0.851866 0.629567 0.918303 0.205008 0.970033 
6  0.758121 0.066677 0.433014 0.005454 0.338596 
7  0.561382 0.968078 0.586736 0.817569 0.842106 
8  0.246986 0.829720 0.522371 0.854840 0.887886 
9  0.709550 0.591733 0.919168 0.568988 0.849380 
10  0.997787 0.084709 0.664845 0.808106 0.872628 
11  0.008661 0.449826 0.841896 0.307360 0.092581 
12  0.727409 0.791167 0.518371 0.691875 0.095718 
13  0.928342 0.247725 0.754204 0.468484 0.663773 
14  0.934902 0.692837 0.367644 0.061359 0.381885 
15  0.828492 0.026166 0.050765 0.524551 0.296122 
16  0.589907 0.775721 0.061765 0.033213 0.793401 
17  0.532189 0.678184 0.747391 0.199283 0.349949 

Perf không phải là quá xấu với phương pháp này (nó có thể là một cảm ứng chậm hơn trong 0.9.0):

In [19]: %time result = df.unstack(0).shift(1).stack() 
CPU times: user 1.46 s, sys: 0.24 s, total: 1.70 s 
Wall time: 1.71 s 
+0

Đó là một cải tiến lớn! Điều đó mất 6,6 s cho tôi dưới 0.8.1; hy vọng tuần sau chúng tôi sẽ cài đặt 0.9.0 để tôi có thể thử điều đó. –

+0

Một điểm khác biệt là vì nó giảm các mục NaN được tạo ra bởi shift() trên stack(), nó có ít hàng hơn so với trước đó, nhưng điều đó được chú ý trong phép nối(). (Và tôi đã có nghĩa là sự thay đổi (-1), đó là một tính toán tỷ lệ nguy hiểm, do đó, nó nhìn về phía trước.) –

+0

Cải tiến hiệu suất tôi đã thực hiện là trong thân cây. Làm việc để sớm phát hành bản phát hành mới –

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