我正在编写一个使用HMM和Viterbi算法提出拼写错误修正的代码。在某些时候,对于文本中的每个单词,我必须执行以下操作。 (假设我有10,000个单词)
#FYI Windows 10, 64bit, interl i7 4GRam, Python 2.7.3
import numpy as np
import pandas as pd
for k in range(10000):
tempWord = corruptList20[k] #Temp word read form the list which has all of the words
delta = np.zeros(26, len(tempWord)))
sai = np.chararray(26, len(tempWord)))
sai[:] = '@'
# INITIALIZATION DELTA
for i in range(26):
delta[i][0] = #CALCULATION matrix read and multiplication each cell is different
# INITILIZATION END
# 6.DELTA CALCULATION
for deltaIndex in range(1, len(tempWord)):
for j in range(26):
tempDelta = 0.0
maxDelta = 0.0
maxState = ''
for i in range(26):
# CALCULATION to fill each cell involve in:
# 1-matrix read and multiplication
# 2 Finding Column Max
# logical operation and if-then-else operations
# 7. SAI BACKWARD TRACKING
delta2 = pd.DataFrame(delta)
sai2 = pd.DataFrame(sai)
proposedWord = np.zeros(len(tempWord), str)
editId = 0
for col in delta2.columns:
# CALCULATION to fill each cell involve in:
# 1-matrix read and multiplication
# 2 Finding Column Max
# logical operation and if-then-else operations
editList20.append(''.join(editWord))
#END OF LOOP
正如您所看到的那样,它涉及计算机,当我运行它时需要花费太多时间来运行。 目前我的笔记本电脑被盗,我在Windows 10,64bit,4GRam,Python 2.7.3
上运行我的问题:任何人都可以看到我可以用来优化的任何一点吗?我是否必须在循环进入下一轮之前删除我在循环中创建的矩阵以使内存空闲或自动完成?
在以下评论后,使用xrange
代替range
,效果几乎提高了 30%。我在此更改后添加了屏幕截图。
答案 0 :(得分:4)
我认为range
讨论没有太大区别。使用Python3,其中range
是迭代器,在迭代之前将其扩展到列表中不会改变时间。
In [107]: timeit for k in range(10000):x=k+1
1000 loops, best of 3: 1.43 ms per loop
In [108]: timeit for k in list(range(10000)):x=k+1
1000 loops, best of 3: 1.58 ms per loop
使用numpy
和pandas
加速循环的真正关键是用在整个数组或数据帧上运行的编译操作替换它们。但即使在纯Python中,也要专注于简化迭代的内容,而不是迭代机制。
======================
for i in range(26):
delta[i][0] = #CALCULATION matrix read and multiplication
一个小改动:delta[i, 0] = ...
;这是寻址单个元素的数组方式;在功能上它通常是相同的,但意图更清晰。但是想想,你能不能将所有列都设置为一次?
delta[:,0] = ...
====================
N = len(tempWord)
delta = np.zeros(26, N))
etc
在紧密循环中,像这样的临时变量可以节省时间。这不紧,所以这里只是增加了清晰度。
===========================
这个丑陋的嵌套三重循环;诚然26步不大,但26 * 26 * N是:
for deltaIndex in range(1,N):
for j in range(26):
tempDelta = 0.0
maxDelta = 0.0
maxState = ''
for i in range(26):
# CALCULATION
# 1-matrix read and multiplication
# 2 Finding Column Max
# logical operation and if-then-else operations
专注于用数组操作替换它。这是需要更改的3条注释行,而不是迭代机制。
=====
使proposedWord
列表而不是数组可能更快。小列表操作通常比第一个更快,因为numpy
数组具有创建开销。
In [136]: timeit np.zeros(20,str)
100000 loops, best of 3: 2.36 µs per loop
In [137]: timeit x=[' ']*20
1000000 loops, best of 3: 614 ns per loop
在创建'空'列表时,你必须要小心,这些元素是真正独立的,而不仅仅是同一个东西的副本。
In [159]: %%timeit
x = np.zeros(20,str)
for i in range(20):
x[i] = chr(65+i)
.....:
100000 loops, best of 3: 14.1 µs per loop
In [160]: timeit [chr(65+i) for i in range(20)]
100000 loops, best of 3: 7.7 µs per loop
答案 1 :(得分:2)
正如评论中所指出的,range
的行为在Python 2和3之间发生了变化。
在2中,range
构造一个填充了数字的整个列表以进行迭代,然后遍历列表。在紧密循环中执行此操作非常昂贵。
在3中,range
构造了一个简单的对象(据我所知),只包含3个数字:起始编号,步长(数字之间的距离)和结束编号。使用简单的数学运算,您可以计算范围内的任何点,而不是必须迭代。当整个列表被交互时,这使得“随机访问”O(1)而不是O(n),并且防止创建昂贵的列表。
在2中,使用xrange
迭代范围对象而不是列表。
(@ Tom:如果你发表答案,我会删除这个)。
答案 2 :(得分:1)
由于缺少代码,很难确切地知道你需要做什么,但很明显你需要学习如何对你的numpy代码进行矢量化。这可以带来100倍的加速。
你可以摆脱所有内部for循环并用向量化操作替换它们。
例如。而不是
for i in range(26):
delta[i][0] = #CALCULATION matrix read and multiplication each cell is differen
DO
delta[:, 0] = # Vectorized form of whatever operation you were going to do.