我正在用Python生成共现矩阵(2000X2000)。
我的代码目前每次迭代需要120秒,完成运行需要364小时。我在Google中运行这个代码,内存为25 in。
该代码可以很好地处理10行语料库和5个单词的小数据。是否有更好的方法来完成这项任务或加快这一进程?
tqdm是必需的,因为如果代码运行时间超过12小时,那么它就会与Google断开连接。
coocur_matrix = np.zeros((len(voca), len(voca)),np.float64)#python
from tqdm import tqdm
window_size=5
corpus=corpu1
vocab = voca
for word1 in tqdm(vocab):
for word2 in vocab:
for sent in corpus:
doc_tokens = []
doc_tokens=sent.split()
p1= [i for i in range(len(doc_tokens)) if doc_tokens[i] == word1]
p2= [i for i in range(len(doc_tokens)) if doc_tokens[i] == word2]
for k in p1:
print(9)
for l in p2:
if (abs(l-k)<=window_size):
if(word1!=word2):
coocur_matrix[vocab.index(word1),vocab.index(word2)] += 1
print(coocur_matrix)发布于 2020-01-15 07:52:51
您的代码在视觉上没有吸引力。您有多个PEP 8违规行为,并且您的变量名称实际上无法说明问题。您有两个缩进空间,这在Python中几乎是闻所未闻的。如果我们将您的代码移动到一个函数中并执行一些清理,我们可以得到如下内容:
import numpy as np
def get_indexes(tokens, word):
return [
index
for index, token in enumerate(tokens)
if token == word
]
def co_occurrence_matrix(corpus, vocabulary, window_size=5):
matrix = np.zeros((len(vocabulary), len(vocabulary)), np.float64)
for word_1 in vocabulary:
for word_2 in vocabulary:
for sent in corpus:
tokens = sent.split()
tokens_1 = get_indexes(tokens, word_1)
tokens_2 = get_indexes(tokens, word_2)
for k in tokens_1:
for l in tokens_2:
if abs(l - k) > window_size:
continue
if word_1 == word_2:
continue
matrix[
vocabulary.index(word_1),
vocabulary.index(word_2),
] += 1
return matrix
print(co_occurrence_matrix(corpu1, voca))现在看起来不算太糟,但看起来并不是很好。从这里我们可以清楚地看到,word_1和word_2是在前两个循环中定义的,但是check word_1 == word_2位于循环的最内部级别。这意味着您在sent、tokens_1和tokens_2上进行不必要的循环。这些循环总数约为12000000,毫无用处,浪费时间。
虽然很难看到,但是vocabulary.index(word_1)中有一个for循环。不然它是怎么得到指数的?这意味着您要循环2000次,这是一种浪费,因为您可以在遍历vocabulary时定义一个变量来存储索引。
您不需要在vocabulary上迭代,只需在corpus上迭代即可。这是因为如果word_1或word_2不在tokens中,那么for循环将在空列表上迭代,因此什么也不会做。因此,我们可以从word_1和word_2中得到corpus。
因为vocabulary只包含corpus中的前2000个单词。那么,简单的循环翻转仍然会浪费一些周期。所以我们只需将sent过滤成vocabulary中的。为了实现这一点,我选择使用闭包,因为我认为它使代码更简洁,更易于阅读。这是因为我没有Python3.7上的walrus,并且希望使用dict.get,而不是每个令牌的每个过滤器执行两个字典查找。
import numpy as np
import itertools
def by_indexes(iterable):
output = {}
for index, key in enumerate(iterable):
output.setdefault(key, []).append(index)
return output
def co_occurrence_matrix(corpus, vocabulary, window_size=5):
def split_tokens(tokens):
for token in tokens:
indexs = vocabulary_indexes.get(token)
if indexs is not None:
yield token, indexs[0]
matrix = np.zeros((len(vocabulary), len(vocabulary)), np.float64)
vocabulary_indexes = by_indexes(vocabulary)
for sent in corpus:
tokens = by_indexes(split_tokens(sent.split())).items()
for ((word_1, x), indexes_1), ((word_2, y), indexes_2) in itertools.permutations(tokens, 2):
for k in indexes_1:
for l in indexes_2:
if abs(l - k) <= window_size:
matrix[x, y] += 1
return matrix
print(co_occurrence_matrix(corpu1, voca))这目前还没有完全优化,因为您可以使用combinations而不是permutations,但是这需要镜像矩阵的非空值。这很可能是运行所需时间的一半,但需要额外的代码。
这是完全假设的答案。这意味着使用两次dict[]而不是dict.get可能会更快。这也意味着,由于Python的方式,我所做的许多假设可能无法转化为性能好处。
https://codereview.stackexchange.com/questions/235633
复制相似问题