Python 嵌套循环Numpy数组:是否可以矢量化?

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

我一直在尝试加速下面的代码,它会查找一个索引,从列表“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, 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)我们只希望.String
count
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]])