python程序的优化经验
2015-12-24 19:44
621 查看
经验一:
在机器学习算法中,有时候会写多重for循环,在多重循环的循环体内会调用某些工具函数。这时候,工具函数的效率就非常关键,因为工具函数经常会被调用100w+次。如果工具函数多执行10000次,那么就要整个for循环跑完就要多执行100亿次。
分析:上述4层for循环,第一层12次,第二层3,第三次4次,第四层10w+。总共循环体需要执行1000w+次左右。并且在循环体中,需要调用函数cosSim(normUserVec,normClassVec)。刚开始我没注意到,在cosSim函数里面有些无意义的操作,导致程序非常慢。无意义的操作后来注释掉,程序性能就提高。注释掉的函数vecLength()是比较耗时的,每次只需1000运算,那么1000*1000w=100亿次操作。
经验二:多重for循环,最好把循环次数多的循环放在最内层。并且,如果能在外层循环就计算出结果,就不放到内层循环里面
并且,上述两条语句可以在外层循环计算得到结果,就不要放到内层循环里面计算。效率低下。
经验三:
如果需要查询元素达到上亿次,那么就不要把待查询的元素放在list里面,因为list的查询是遍历法,即 if a in list 采用的是遍历的方法去查询,所以,这时候,就要把待查询的元素放在dict或set里面,用空间换时间。
经验四:
在多层循环体内部,最好不要调用函数,因为调用函数需要出栈,入栈操作,会非常耗时间。c++可以使用内联函数,python好像没有这个机制,所以,多重for循环尽量避免调用函数。上面的例子中,多重for循环调用了函数cosSim。是程序性能上的瓶颈,最好不要调用,直接在循环体内实现。
解析:上述程序中,将cosSim函数直接在循环体内实现,使性能有了极大的提高,可以看出在循环体内调用函数确实是非常耗时的。
在机器学习算法中,有时候会写多重for循环,在多重循环的循环体内会调用某些工具函数。这时候,工具函数的效率就非常关键,因为工具函数经常会被调用100w+次。如果工具函数多执行10000次,那么就要整个for循环跑完就要多执行100亿次。
userIdList = normUserCountVectDict.keys() actionTypeList = ['0','2','3'] fieldList = ['cat_id','seller_id','brand_id','item_id'] #建立行为的下标映射,方便存储相似性得分 fieldIndex = {} index = 0 for action in actionTypeList: for field in fieldList: fieldIndex[action+'#'+field] = index index += 1 #这个循环体必须得优化 #因为userIdList的长度是3w+ #循环最多次的循环放在最内层 for classNum in classNumList: for actionType in actionTypeList: for field in fieldList: normClassVec = normClassCountVectDict[classNum][actionType][field] index = fieldIndex[actionType+'#'+field] for userId in userIdList: normUserVec = normUserCountVectDict[userId][actionType][field] #有些用户的特征向量会是零向量,比如用户无点击行为,必须考虑这种异常情况 if len(normUserVec) == 0: similarity[classNum][userId][index] = 0 else: similarity[classNum][userId][index] = cosSim(normUserVec,normClassVec)
分析:上述4层for循环,第一层12次,第二层3,第三次4次,第四层10w+。总共循环体需要执行1000w+次左右。并且在循环体中,需要调用函数cosSim(normUserVec,normClassVec)。刚开始我没注意到,在cosSim函数里面有些无意义的操作,导致程序非常慢。无意义的操作后来注释掉,程序性能就提高。注释掉的函数vecLength()是比较耗时的,每次只需1000运算,那么1000*1000w=100亿次操作。
def cosSim(dictA,dictB): #先判断dictA,dictB的模长是否为1 #这个太误差检验太耗时,因为这个函数频繁被调用,上亿次,核心函数 #lengthA = vecLength(dictA) #lengthB = vecLength(dictB) #数值计算问题,不适合用lengthA=1来判断是否已归一化 #if (abs(lengthA-1)>0.01) or (abs(lengthB-1)>0.01): # print dictA # print lengthA # print "error:vector not normal" commonKey = set(dictA.keys()) & set(dictB.keys()) sim = 0.0 for key in commonKey: sim += dictA[key]*dictB[key] return sim
经验二:多重for循环,最好把循环次数多的循环放在最内层。并且,如果能在外层循环就计算出结果,就不放到内层循环里面
#这个循环体必须得优化 #因为userIdList的长度是3w+ #循环最多次的循环放在最内层 for classNum in classNumList: for actionType in actionTypeList: for field in fieldList: normClassVec = normClassCountVectDict[classNum][actionType][field] index = fieldIndex[actionType+'#'+field] for userId in userIdList: normUserVec = normUserCountVectDict[userId][actionType][field] #有些用户的特征向量会是零向量,比如用户无点击行为,必须考虑这种异常情况 if len(normUserVec) == 0: similarity[classNum][userId][index] = 0 else: similarity[classNum][userId][index] = cosSim(normUserVec,normClassVec)分析:上述userId的循环次数是最多的,所以放在内层循环。
normClassVec = normClassCountVectDict[classNum][actionType][field] index = fieldIndex[actionType+'#'+field]
并且,上述两条语句可以在外层循环计算得到结果,就不要放到内层循环里面计算。效率低下。
经验三:
如果需要查询元素达到上亿次,那么就不要把待查询的元素放在list里面,因为list的查询是遍历法,即 if a in list 采用的是遍历的方法去查询,所以,这时候,就要把待查询的元素放在dict或set里面,用空间换时间。
经验四:
在多层循环体内部,最好不要调用函数,因为调用函数需要出栈,入栈操作,会非常耗时间。c++可以使用内联函数,python好像没有这个机制,所以,多重for循环尽量避免调用函数。上面的例子中,多重for循环调用了函数cosSim。是程序性能上的瓶颈,最好不要调用,直接在循环体内实现。
for classNum in classNumList:
for actionType in actionTypeList:
for field in fieldList:
normClassVec = normClassCountVectDict[classNum][actionType][field] index = fieldIndex[actionType+'#'+field]dictAKeys = set(normClassVec.keys())
for userId in userIdList:
normUserVec = normUserCountVectDict[userId][actionType][field]
#有些用户的特征向量会是零向量,比如用户无点击行为,必须考虑这种异常情况
if len(normUserVec) == 0:
similarity[classNum][userId][index] = 0
else:
#内层循环里面不适合调用函数,耗时
dictBKeys = set(normUserVec.keys())
commonKey = dictAKeys & dictBKeys
sim = 0.0
for key in commonKey:
sim += normClassVec[key]*normUserVec[key]
similarity[classNum][userId][index] = sim
解析:上述程序中,将cosSim函数直接在循环体内实现,使性能有了极大的提高,可以看出在循环体内调用函数确实是非常耗时的。
相关文章推荐
- python的urllib和urllib2的区别
- 排序算法—直接插入排序算法分析与实现(Python)
- python 调试
- [Python]croppic 裁剪图片的Python后台实现
- python的urllib
- Python类Nagios监控软件开发实战视频课程
- Python与机器人技术
- python的opencv使用
- C# 服务里面调用Python.exe 来执行python文件
- python
- python 各类距离公式实现
- python 抓取百度搜索结果的快照排名信息
- python发送邮件脚本(支持多个附件,中文)
- Python点滴
- Python的操作符
- Python的数据类型
- Perceptron Learning Algorithm(python实现)
- Python基础:绑定和方法调用
- python的一些错误提示
- python的HTMLParser