2017-04-03 36 views

回答

5

您需要filtration

df = df.groupby('letter').filter(lambda x: (x['number'] == 0).any()) 
print (df) 
    letter number 
0  a  2 
1  a  0 
5  c  1 
6  c  0 
7  c  2 

transform另一種解決方案,其中通過boolean indexing得到0行大小和過濾:

print (df.groupby('letter')['number'].transform(lambda x: (x == 0).sum())) 
0 1 
1 1 
2 0 
3 0 
4 0 
5 1 
6 1 
7 1 
Name: number, dtype: int64 

df = df[df.groupby('letter')['number'].transform(lambda x: (x == 0).sum()) > 0] 
print (df) 
    letter number 
0  a  2 
1  a  0 
5  c  1 
6  c  0 
7  c  2 

編輯:

更快未使用groupby,更好是locisin

df1 = df[df['letter'].isin(df.loc[df['number'] == 0, 'letter'])] 
print (df1) 
    letter number 
0  a  2 
1  a  0 
5  c  1 
6  c  0 
7  c  2 

與其它解決方案相比:

In [412]: %timeit df[df['letter'].isin(df[df['number'] == 0]['letter'])] 
1000 loops, best of 3: 815 µs per loop 

In [413]: %timeit df[df['letter'].isin(df.loc[df['number'] == 0, 'letter'])] 
1000 loops, best of 3: 657 µs per loop 
+0

工程就像一個魅力。驚人。謝謝 ! :) – user2475110

+0

我想他知道他需要一個過濾器,他需要的是groupby! – CodeMonkey

+1

@CodeMonkey - 謝謝;) – jezrael

3

您還可以通過找出哪些字母保持然後使用isin做到這一點沒有groupby。我認爲這是一個有點整潔個人:

>>> letters_to_keep = df[df['number'] == 0]['letter'] 
>>> df_reduced = df[df['letter'].isin(letters_to_keep)] 
>>> df_reduced 
    letter number 
0  a  2 
1  a  0 
5  c  1 
6  c  0 
7  c  2 

我懷疑這會比做一個groupby更快,這可能不是與此有關,但!一個簡單的timeit將表明這種情況:

>>> %%timeit 
... df.groupby('letter').filter(lambda x: (x['number'] == 0).any()) 
100 loops, best of 3: 2.26 ms per loop 

>>> %%timeit 
... df[df['letter'].isin(df[df['number'] == 0]['letter'])] 
1000 loops, best of 3: 820 µs per loop 
+0

是的,你是絕對正確的,'groupby'很慢。我稍微修改你的解決方案以獲得更快的解決方案,查看我的答案 – jezrael

+0

沒有直接想到'loc',是的,看起來不錯。 – bastewart

+0

是的,它與布爾索引完美結合 - 按掩碼和列名過濾。 – jezrael

相關問題