2016-02-28 2 views
5

У меня есть dataframe, что я, как это подмножество:Выражая панды подмножество с использованием трубы

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() 

Как выразить это с помощью оператора панды трубы?

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

Я не понимаю, почему использование 'pipe' было бы полезно здесь. 'df [(df.a> = 2) & (df.b <= 8)]. groupby ('x'). mean()' будет делать то же самое, не так ли? – jme

+0

Это правда @jme, это пример игрушки, и в моем более крупном коде у меня больше шагов. Кроме того, оператор '.' заставляет все выглядеть аккуратно. – user308827

+0

Это либо дежа-вю, либо [дубликат] (http://stackoverflow.com/questions/35045805) :-) – Primer

ответ

2

Пока вы можете категоризировать шаг, как то, что возвращает DataFrame и принимает DataFrame (возможно, с большим количеством аргументов), то вы можете использовать pipe. Есть ли преимущество для этого, это еще один вопрос.

Здесь, например, вы можете использовать

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

Обратите внимание, как первый этап лямбда, который принимает 3 аргумента, с 2 и 8, переданного в качестве параметров. Это не единственный способ сделать это - это эквивалентно

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

Также обратите внимание, что вы можете использовать

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

Здесь лямбда принимает df_, но работает на df, а второй pipe было заменен на groupby.

  • Первое изменение работает здесь, но является gragile. Это происходит работать, так как это первый трубы этапе. Если это будет более поздний этап, он может взять DataFrame с одним измерением и попытаться отфильтровать его на маске с другим измерением, например.

  • Второе изменение - это хорошо. На лице я думаю, что это более читаемо. В принципе, все, что принимает DataFrame и возвращает один, может быть вызвано напрямую или через pipe.

+0

, спасибо @Ami, вы используете 'df_' в своей лямбде, просто будет работать' df'? – user308827

+0

а также, могу ли я до сих пор иметь .groupby not .pipe (lambda ... .groupby)? – user308827

+1

Добро пожаловать. См. Обновления. –

1

Вы можете попробовать, но я думаю, что это более сложная:

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

спасибо @jezrael, у вас есть действительная сложность по задаче – user308827

1

Я считаю, что этот метод ясно в отношении ваших шагов фильтрации и последующих операций. Однако использование loc[(mask1) & (mask2)], вероятно, более показательно.

>>> (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 

В качестве альтернативы:

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

спасибо @ Александр, могу ли я еще иметь .groupby not .pipe (pd.DataFrame.groupby, 'x'), т.е. тот же способ использования .groupby, как в моем коде выше – user308827