2016-02-28 33 views
5

Tôi có một dataframe mà tôi tập hợp con như thế này:gấu trúc Bày tỏ nhóm sử dụng ống

a b x y 
0 1 2 3 -1 
1 2 4 6 -2 
2 3 6 6 -3 
3 4 8 3 -4 

df = df[(df.a >= 2) & (df.b <= 8)] 
df = df.groupby(df.x).mean() 

Làm thế nào để thể hiện điều này bằng cách sử dụng toán tử ống gấu trúc?

df = (df 
     .pipe((x.a > 2) & (x.b < 6) 
     .groupby(df.x) 
     .apply(lambda x: x.mean()) 
+1

Tôi không thấy lý do tại sao sử dụng 'pipe' sẽ hữu ích ở đây. 'df [(df.a> = 2) & (df.b <= 8)]. groupby ('x'). mean()' sẽ làm điều tương tự, đúng không? – jme

+0

đó là sự thật @ jme, đây là một ví dụ đồ chơi và trong mã lớn hơn của tôi, tôi có nhiều bước hơn. Cộng với toán tử '.' làm cho mọi thứ trông gọn gàng hơn. – user308827

+0

Đây là một trong hai deja vu hoặc [duplicate] (http://stackoverflow.com/questions/35045805) :-) – Primer

Trả lời

2

Chừng nào bạn có thể phân loại một bước như cái gì mà trả về một DataFrame, và mất một DataFrame (với các đối số có thể nhiều hơn), sau đó bạn có thể sử dụng pipe. Cho dù có một lợi thế để làm như vậy, là một câu hỏi khác.

Ở đây, ví dụ, bạn có thể sử dụng Thông báo

df\ 
    .pipe(lambda df_, x, y: df_[(df_.a >= x) & (df_.b <= y)], 2, 8)\ 
    .pipe(lambda df_: df_.groupby(df_.x))\ 
    .mean() 

cách giai đoạn đầu tiên là một lambda mà mất 3 đối số, với 2 và 8 thông qua như là tham số. Đó không phải là cách duy nhất để làm như vậy - nó tương đương với

.pipe(lambda df_: df_[(df_.a >= 2) & (df_.b <= 8)])\ 

Cũng lưu ý rằng bạn có thể sử dụng

df\ 
    .pipe(lambda df_, x, y: df[(df.a >= x) & (df.b <= y)], 2, 8)\ 
    .groupby('x')\ 
    .mean() 

Ở đây lambda mất df_, nhưng hoạt động trên df, và lần thứ hai pipe đã được thay thế bằng groupby.

  • Thay đổi đầu tiên hoạt động ở đây, nhưng là gragile. Nó xảy ra để hoạt động vì đây là giai đoạn đầu tiên đường ống đầu tiên. Nếu nó sẽ là một giai đoạn sau, nó có thể mất một DataFrame với một chiều, và cố gắng để lọc nó trên một mặt nạ với kích thước khác, ví dụ.

  • Thay đổi thứ hai là tốt. Đối mặt, tôi nghĩ nó dễ đọc hơn. Về cơ bản, bất cứ điều gì mà có một DataFrame và trả về một, có thể được gọi trực tiếp hoặc thông qua pipe.

+0

nhờ @Ami, bạn sử dụng 'df_' trong lambda của bạn, sẽ chỉ' df' làm việc quá? – user308827

+0

và cũng có thể, tôi vẫn có thể .groupby không .pipe (lambda ... .groupby)? – user308827

+1

Bạn được chào đón. Xem cập nhật. –

1

Bạn có thể thử, nhưng tôi nghĩ rằng đó là phức tạp hơn:

print df[(df.a >= 2) & (df.b <= 8)].groupby(df.x).mean() 
    a b x y 
x     
3 4.0 8 3 -4.0 
6 2.5 5 6 -2.5 


def masker(df, mask): 
    return df[mask] 

mask1 = (df.a >= 2) 
mask2 = (df.b <= 8)  

print df.pipe(masker, mask1).pipe(masker, mask2).groupby(df.x).mean() 
    a b x y 
x     
3 4.0 8 3 -4.0 
6 2.5 5 6 -2.5 
+0

cảm ơn @ jezrael, bạn có một điểm hợp lệ tái phức tạp – user308827

1

tôi tin rằng phương pháp này là rõ ràng đối với các bước lọc của bạn và các hoạt động tiếp theo với. Tuy nhiên, việc sử dụng loc[(mask1) & (mask2)] có thể hiệu quả hơn.

>>> (df 
    .pipe(lambda x: x.loc[x.a >= 2]) 
    .pipe(lambda x: x.loc[x.b <= 8]) 
    .pipe(pd.DataFrame.groupby, 'x') 
    .mean() 
    ) 

    a b y 
x    
3 4.0 8 -4.0 
6 2.5 5 -2.5 

Hoặc:

(df 
.pipe(lambda x: x.loc[x.a >= 2]) 
.pipe(lambda x: x.loc[x.b <= 8]) 
.groupby('x') 
.mean() 
) 
+0

nhờ @Alexander, tôi vẫn có thể có .groupby không phải .pipe (pd.DataFrame.groupby, 'x') tức là cách sử dụng .groupby như trong mã của tôi ở trên – user308827

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