使用Pandas得到阿布分布功能进行运算是,经常需要创建临时对象,这样会占用很大的内存和使用较长的计算时间。pandas为了解决性能问题,引入了eval()和query()函数,他们都依赖Numexpr包,运算过程中不需要费力地配置中间数组。
一、使用Pandas.eval()实现高性能运算
1、pandas中的函数eval()能够将字符串对象转化为有效的表达式,进行求值运算并返回结果;
一般地,运算简单或DataFrame数据量较少之时不适用eval()函数,在DataFrame大于10000行时使用eval(),性能会得到明显提升。
>>>import numpy as np
>>>import pandas as pd
>>>nrows=20000
>>>nclos=200
>>>df1,df2,df3,df4 = [pd.DataFrame(np.random.randn(nrows,nclos)) for i in range(4)]
>>>%timeit df1+df2+df3+df4
50.8 ms ± 3.11 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>>%timeit pd.eval('df1+df2+df3+df4')
23.6 ms ± 888 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
其中:魔术命令%timeit可自动多次执行语句,产生一个较为精准的平均执行时间。
使用np.allclose()比较两个数组是否完全相同,结果为True表示eval函数计算结果与普通Pandas计算结果一致。
>>>np.allclose(df1+df2+df3+df4,pd.eval('df1+df2+df3+df4'))
True
2、eval()支持的运算方式
eval()函数支持多种运算方式,如:算数运算、比较运算和布尔运算,同时也支持对象属性与索引的表达方式;
eval()函数目前还不支持函数条用,if条件语句,循环语句及更为复杂的运算。
3、DataFrame.eval()实现列间运算
>>>df.eval("sex=='female'and score_math>80")
0 False
1 True
2 True
3 False
4 True
5 False
6 False
7 False
8 False
dtype: bool
#新增列
>>> df.eval('sum_score = score_math + score_music',inplace=True)
>>> df
class sex score_math score_music sum_score
0 A male 95 79 174
1 A female 96 90 186
2 B female 85 85 170
3 C male 93 92 185
4 B female 84 90 174
5 B male 88 70 158
6 C male 59 89 148
7 A male 88 86 174
8 B male 89 74 163
#修改列
>>> df.eval('score_math = score_math +5')
class sex score_math score_music sum_score
0 A male 100 79 174
1 A female 101 90 186
2 B female 90 85 170
3 C male 98 92 185
4 B female 89 90 174
5 B male 93 70 158
6 C male 64 89 148
7 A male 93 86 174
8 B male 94 74 163
4、DataFrame.eval()使用局部变量
通过@符号使用Python的局部变量,@符号表示其后紧随的是一个变量名称而不是列名称,如下:
>>> add = pd.Series([1,2,3,4,5,6,7,8])
>>> df.eval('score_math+@add')
0 96.0
1 98.0
2 88.0
3 97.0
4 89.0
5 94.0
6 66.0
7 96.0
8 NaN
dtype: float64
二、DataFrame.query()方法
query()可以实现查询过滤的功能,其用于与DataFrame.eval()类似。
>>> df.query("score_math>85 & score_music>85")
class sex score_math score_music sum_score
1 A female 96 90 186
3 C male 93 92 185
7 A male 88 86 174
注意:DtaFrame.eval()尽心相同运算时返回的是布尔值