2017-05-08 95 views
3

我有一個數據幀Pandas中的自定義布爾過濾?

    0   1   2   3  Marketcap 
0 1.707280 0.666952 0.638515 -0.061126 2.291747  1.71B 
1 -1.017134 1.353627 0.618433 0.008279 0.148128  1.82B 
2 -0.774057 -0.165566 -0.083345 0.741598 -0.139851  1.1M 
3 -0.630724 0.250737 1.308556 -1.040799 1.064456 30.92M 
4 2.029370 0.899612 0.261146 1.474148 -1.663970 476.74k 
5 2.029370 0.899612 0.261146 1.474148 -1.663970  -1 

是否有某種形式的自定義過濾器的方法,這將讓Python的知道B> M> K +

說我想過濾,df[df.Marketcap > 35.00M],有沒有一個聰明或乾淨的方法來做到這一點?具有M或B的值使得該值非常易讀並易於區分。

謝謝。

編輯:重新打開線程作爲最大U的答案,而優秀似乎產生一個熊貓的bug,我們在Github上打開一個問題。

回答

2

來源DF:

In [176]: df 
Out[176]: 
        0   1   2   3 Market Cap 
0 1.707280 0.666952 0.638515 -0.061126 2.291747  1.71B 
1 -1.017134 1.353627 0.618433 0.008279 0.148128  1.82B 
2 -0.774057 -0.165566 -0.083345 0.741598 -0.139851  1.1M 
3 -0.630724 0.250737 1.308556 -1.040799 1.064456  30.92M 
4 2.029370 0.899612 0.261146 1.474148 -1.663970 476.74k 
5 2.029370 0.899612 0.261146 1.474148 -1.663970   -1 

解決方案:

to_replace = ['\d+\s*[Kk]','\d+\s*[Mm]','\d+\s*[Bb]', '-1', 'N/A'] 
value = [1000,1000000,1000000000, 1, 1] 

mask = df.assign(
    f=df['Market Cap'].replace(to_replace, value, regex=True), 
    Marketcap=pd.to_numeric(df['Market Cap'].str.replace(r'[^\d\.]', ''), errors='coerce') 
).eval("Marketcap * f < 35000000") 

df[mask] 

結果:

In [178]: df[mask] 
Out[178]: 
        0   1   2   3 Market Cap 
2 -0.774057 -0.165566 -0.083345 0.741598 -0.139851  1.1M 
3 -0.630724 0.250737 1.308556 -1.040799 1.064456  30.92M 
4 2.029370 0.899612 0.261146 1.474148 -1.663970 476.74k 
5 2.029370 0.899612 0.261146 1.474148 -1.663970   -1 

PS如果你想在所產生的數據集的變化留下非數值(如N/A):

pd.to_numeric(df['Market Cap'].str.replace(r'[^\d\.]', ''), errors='coerce') 

pd.to_numeric(df['Market Cap'].str.replace(r'[^\d\.]', ''), errors='coerce').fillna('0') 
+0

謝謝!我今天晚些時候會看看它,因爲它看起來有點複雜,需要一些時間。順便說一句,爲了得到這些看起來很乾淨的輸出單元(out [178]等),你是否通過命令行完成Ipython的所有操作,然後複製單元格?我試圖複製Jupyter筆記本輸出單元,但是當我粘貼在這裏時,它非常不整潔。 – Moondra

+1

@moondra,是的,對不起,我更喜歡iPython,因爲我是一個控制檯的人;-) – MaxU

+0

嗨,最大,我有一個關於'掩碼'代碼部分的問題; 'df.assign'中的第一個'f'創建一個新列?第二部分「Marketcap = pd.to_numeric」也在創建一個新列?我在理解這部分時遇到了一些麻煩。謝謝! – Moondra

3

這是不是超級乾淨,但它的伎倆,並且不使用任何的Python迭代:

代碼:

# Create a separate column (which you can omit later) that converts 'Marketcap' strings to numbers 
df['cap'] = df.loc[df['Marketcap'].str.contains('B'), 'Marketcap'].str.replace('B','').astype(float) * 1000 
df['cap'].fillna(df.loc[df['Marketcap'].str.contains('M'), 'Marketcap'].str.replace('M',''), inplace = True) 

# For pandas pre-0.20.0 (<May 2017) 
print df.ix[df['cap'].astype(float) > 35, :-1] 

# For pandas 0.20.0+ (.ix[] deprecated) 
print df.iloc[df[df['cap'].astype(float) > 35].index, :-1] 

# Or, alternate pandas 0.20.0+ option (thanks @Psidom) 
print df[df['cap'].astype(float) > 35].iloc[:,:-1] 

輸出:

  0   1   2   3   4 Marketcap 
0 1.707280 0.666952 0.638515 -0.061126 2.291747  1.71B 
1 -1.017134 1.353627 0.618433 0.008279 0.148128  1.82B 
4 2.029370 0.899612 0.261146 1.474148 -1.663970 100.9M 
+0

謝謝。我剛剛意識到我的數據框中也有'k'(1000),所以我更新了OP中的數據幀,以反映這一點。你能夠更新你的代碼來反映這一點嗎?非常感謝。 – Moondra

+0

moondra - @ MaxU的解決方案比我的要乾淨得多,我不認爲有必要重新發明他的車輪。 – pshep123

2

更新:

In [44]: df 
Out[44]: 
      0   1   2   3   4 Marketcap 
0 1.707280 0.666952 0.638515 -0.061126 2.291747  1.71B 
1 -1.017134 1.353627 0.618433 0.008279 0.148128  1.82B 
2 -0.774057 -0.165566 -0.083345 0.741598 -0.139851  1.1M 
3 -0.630724 0.250737 1.308556 -1.040799 1.064456 30.92M 
4 2.029370 0.899612 0.261146 1.474148 -1.663970 476.74k 
5 2.029370 0.899612 0.261146 1.474148 -1.663970  -1 

In [45]: df[pd.eval(df.Marketcap.replace(['[Kk]','[Mm]','[Bb]'], 
             ['*10**3','*10**6','*10**9'], regex=True) \ 
         .add(' < 35*10**6'))] 
Out[45]: 
      0   1   2   3   4 Marketcap 
2 -0.774057 -0.165566 -0.083345 0.741598 -0.139851  1.1M 
3 -0.630724 0.250737 1.308556 -1.040799 1.064456 30.92M 
4 2.029370 0.899612 0.261146 1.474148 -1.663970 476.74k 
5 2.029370 0.899612 0.261146 1.474148 -1.663970  -1 

我會做這種方式:

In [13]: df[pd.eval(df.Marketcap.replace(['M','B'],['','*1000'], regex=True).add(' > 35'))] 
Out[13]: 
      0   1   2   3   4 Marketcap 
0 1.707280 0.666952 0.638515 -0.061126 2.291747  1.71B 
1 -1.017134 1.353627 0.618433 0.008279 0.148128  1.82B 
4 2.029370 0.899612 0.261146 1.474148 -1.663970 100.9M 

說明:

In [14]: df.Marketcap.replace(['M','B'],['','*1000'], regex=True) 
Out[14]: 
0 1.71*1000 
1 1.82*1000 
2   1.1 
3  30.92 
4  100.9 
Name: Marketcap, dtype: object 

In [15]: df.Marketcap.replace(['M','B'],['','*1000'], regex=True).add(' > 35') 
Out[15]: 
0 1.71*1000 > 35 
1 1.82*1000 > 35 
2   1.1 > 35 
3  30.92 > 35 
4  100.9 > 35 
Name: Marketcap, dtype: object 

In [16]: pd.eval(df.Marketcap.replace(['M','B'],['','*1000'], regex=True).add(' > 35')) 
Out[16]: array([True, True, False, False, True], dtype=object) 
+0

很好地完成。去測試代碼。 – Moondra

+0

爲什麼你啓用'regex = True'? – Moondra

+0

如果我有'regex = True',我遇到了這個錯誤; 「PandasExprVisitor」對象沒有「visit_Ellipsis」屬性。如果我將其關閉,則會遇到另一個錯誤,我將其作爲圖像發佈在OP中。有關錯誤的任何想法? – Moondra