1. 过早的优化是万恶之源
开发的时候尽量先保证可读性和松耦合,性能的问题稍微考虑一下就行。开发完成后出现了性能问题后再进行tuning。
2. 优化前使用工具进行性能分析
个人更喜欢line_profiler。看每一行执行的时间占比,也大概知道原因出在什么地方了。自带的profile会深入到包的底层运算逻辑,不是特别清晰。下面是line_profiler的使用方法,个人感觉比装饰器的方式好用太多:
from line_profiler import LineProfiler
import random
def do_stuff(numbers):
s = sum(numbers)
l = [numbers[i]/43 for i in range(len(numbers))]
m = ['hello'+str(numbers[i]) for i in range(len(numbers))]
numbers = [random.randint(1,100) for i in range(1000)]
lp = LineProfiler()
lp_wrapper = lp(do_stuff)
lp_wrapper(numbers)
lp.print_stats()
3. 尽量不要在pandas中使用循环(行遍历)
pandas作为一个非常“高级”的包,为了易用性牺牲了很多效率。在使用循环时,会产生类型推断等额外的操作,而且没法利用到pandas内部的特殊优化。
4. 如果循环很难避免,在循环体中使用numpy做计算
numpy的底层使用C构建的,而且anaconda的中numpy包使用了MKL,可以针对CPU的指令集进行优化,针对于数值或者矩阵运算,还有相当优秀的算法算法来优化,所以效率是相当高的。在很多情景之下,如果核心部分改为numpy的话,说不定就已经解决了问题。
5. 如果numpy效率还是不够理想
可以试试cython,你可以把cython当做新的语言,是python的一个超集。结合了C和python的特性,比如变量声明等要符合C的特性,但是又可以使用numpy的一些包。当编译器事先知道变量的类型可以很好的优化代码,这是纯解释语言天生的缺陷。但是在个人的实际使用中,发现仅仅增加类型声明并没有特别多的提升,可能是相关的计算逻辑已经被numpy优化的差不多了吧。但是这种方法的坏处显而易见,代码的可读性明显降低了。。。
6. 不要使用.ix操作符
尽量使用.loc和.iloc来获取数据。而且.ix未来很快就会在pandas中移除。
7. 在有序列中查找使用pandas.Series.searchsorted
这种查找底层使用二分查找,效率会高很多。
8. 统计某个值出现的次数时
尽量不要使用len(df[df[‘report_month’]==3)这种方式,使用pandas.Series.value_counts效率会更高一点。最快的还是numpy:
np.in1d(normal_reports['report_month'],3).sum()
9. 不要做重复的计算
ticker | date | close |
---|---|---|
000001 | 20160101 | 11 |
000001 | 20180101 | 12 |
000002 | 20160101 | 13 |
000002 | 20180101 | 14 |
假设有3000多只股票,每个股票都取了同样时间范围的2年数据。我现在要把date字段从string类型转化为datetime类型。如果直接用pd.to_datetime(date),那么其实效率奇慢。日期的转化需要一些推断的操作,非常耗时。其实只要第一只股票对于的日期转化后,后面的时间区间都是一样的,不需要做重复的转化,幸好pandas支持map操作,下面的代码会极大的提升效率:
def lookup(s):
"""
This is an extremely fast approach to datetime parsing.
For large data, the same dates are often repeated. Rather than
re-parse these, we store all unique dates, parse them, and
use a lookup to convert all dates.
"""
dates = {date:pd.to_datetime(date) for date in s.unique()}
return s.map(dates)
注意:
1. 上面的一些建议是在本人的开发工作中遇到的情况,有些性能问题是在大量的循环中才会暴露出来。所以在没有实际应用场景的情况下扯性能都是耍流氓。
2. 后面遇到新的case会持续更新,希望不要踩到这么多坑。。。