2017-05-08 86 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