Python 嵌套循环Numpy数组:是否可以矢量化?
我一直在尝试加速下面的代码,它会查找一个索引,从列表“name”中获取一个字符串,并最终计算它在两部分数据中的精确匹配数 这个过程非常缓慢。我读过关于在使用numpy数组时替换for循环的内容,但不确定如何处理/创建带有正则表达式匹配的向量化版本Python 嵌套循环Numpy数组:是否可以矢量化?,python,numpy,Python,Numpy,我一直在尝试加速下面的代码,它会查找一个索引,从列表“name”中获取一个字符串,并最终计算它在两部分数据中的精确匹配数 这个过程非常缓慢。我读过关于在使用numpy数组时替换for循环的内容,但不确定如何处理/创建带有正则表达式匹配的向量化版本 x = np.empty([38000, 8000]) y = np.empty([38000, 8000]) for i in range(0, 38000): for j in range(0, 8000): x[i
x = np.empty([38000, 8000])
y = np.empty([38000, 8000])
for i in range(0, 38000):
for j in range(0, 8000):
x[i, j] = len(re.findall('\\b'+name[index[j]]+'\\b', data[i][1]))
y[i, j] = len(re.findall('\\b'+name[index[j]]+'\\b', data[i][2]))
非常感谢任何见解,矢量化在这里对您没有多大帮助,但避免重复工作将:
patterns = [re.compile('\\b'+name[idx]+'\\b') for idx in index]
for i, row in enumerate(data):
for j, patt in enumerate(patterns):
x[i, j] = len(patt.findall(row[1]))
y[i, j] = len(patt.findall(row[2]))
向量化函数 首先定义一个函数并将其矢量化:
def count_words(word, sentence):
return len(re.findall(r'\b%s\b'%word, sentence))
vcount_words = np.vectorize(count_words)
然后应用(这里的单词是数组800元素数组,数据是3800X2矩阵)
较小的示例适用于此处(5X3):
根据您的数据进行相应调整。这可以通过不在函数中重新编译正则表达式(预编译并索引到其中)来加快速度。我还将在使用for循环在numpy数组上循环时研究numba
但是,这演示了向量化函数方法,您已经“接受”了,现在已经晚了 名称、索引和数据是什么样子的?除非
name
本身包含正则表达式,否则您可以首先使用简单的字符串匹配筛选可能的候选单元格,然后对候选单元格运行正则表达式…index=[0,123,454,…]#1-by-8000
index保存了一个被认为有趣的名称索引name=['dog'、'cat'、…]
name保存了大量字符串(1-by-50000)我们只希望.Stringcount
或np.char.count
的索引编号值比re.findall
快,如果您不需要\b
分隔。如果len(name)
,在编制索引之前编译模式。您可以在开始时编译模式。据我所知,re
模块保留了已编译模式的缓存,因此预编译可能不会有多大帮助。相比于x1中的I,“[len(re.findall('\\b'+'name'+'\\b',I]),我使用[len将x1中的I的速度提高了40%。]``.有趣的是,可能大量的模式溢出了re
模式缓存?我将更新我的答案。vectorize
函数不会加快代码的速度,它只是以一种便于广播和其他数组技巧的方式对代码进行包装。有一个np.char
模块将字符串操作应用于字符串数组。但它无法处理re
所能处理的更奇特的搜索模式。
vcount_words(names, data[:,:1])
names = ['aaa', 'bbb', 'ccc']
data = np.array([['aaa aaa aaa bbb dd', 'ee ff ccc ee ee dd bbb ee'],
['aaa ccc dd aaa ff ff ee', 'dd ccc ee ccc dd ee ff'],
['ee aaa ff ccc ff ee aaa dd bbb', 'aaa'],
['ff ee ccc ccc', 'dd'],
['ccc ee aaa dd', 'ccc bbb ee aaa bbb ff ee']])
x = vcount_words(names, data[:,:1])
# returns >>>
array([[3, 1, 0],
[2, 0, 1],
[2, 1, 1],
[0, 0, 2],
[1, 0, 1]])