【发布时间】:2019-10-11 18:07:36
【问题描述】:
我正在尝试创建一个简单的模型来预测句子中的下一个单词。我有一个大的 .txt 文件,其中包含由 '\n' 分隔的句子。我还有一个词汇文件,其中列出了我的 .txt 文件中的每个唯一单词和一个唯一 ID。我使用词汇文件将语料库中的单词转换为相应的 ID。现在我想制作一个简单的模型,它从 txt 文件中读取 ID 并找到单词对以及在语料库中看到这些单词对的次数。我已经设法写到下面的代码:
tuples = [[]] #array for word tuples to be stored in
data = [] #array for tuple frequencies to be stored in
data.append(0) #tuples array starts with an empty element at the beginning for some reason.
# Adding zero to the beginning of the frequency array levels the indexes of the two arrays
with open("markovData.txt") as f:
contentData = f.readlines()
contentData = [x.strip() for x in contentData]
lineIndex = 0
for line in contentData:
tmpArray = line.split() #split line to array of words
tupleIndex = 0
tmpArrayIndex = 0
for tmpArrayIndex in range(len(tmpArray) - 1): #do this for every word except the last one since the last word has no word after it.
if [tmpArray[tmpArrayIndex], tmpArray[tmpArrayIndex + 1]] in tuples: #if the word pair is was seen before
data[tuples.index([tmpArray[tmpArrayIndex], tmpArray[tmpArrayIndex + 1]])] += 1 #increment the frequency of said pair
else:
tuples.append([tmpArray[tmpArrayIndex], tmpArray[tmpArrayIndex + 1]]) #if the word pair is never seen before
data.append(1) #add the pair to list and set frequency to 1.
#print every 1000th line to check the progress
lineIndex += 1
if ((lineIndex % 1000) == 0):
print(lineIndex)
with open("markovWindowSize1.txt", 'a', encoding="utf8") as markovWindowSize1File:
#write tuples to txt file
for tuple in tuples:
if (len(tuple) > 0): # if tuple is not epmty
markovWindowSize1File.write(str(element[0]) + "," + str(element[1]) + " ")
markovWindowSize1File.write("\n")
markovWindowSize1File.write("\n")
#blank spaces between two data
#write frequencies of the tuples to txt file
for element in data:
markovWindowSize1File.write(str(element) + " ")
markovWindowSize1File.write("\n")
markovWindowSize1File.write("\n")
这段代码似乎在前几千行中运行良好。然后事情开始变慢,因为元组列表越来越大,我必须搜索整个元组列表来检查下一个单词对是否之前出现过。我设法在 30 分钟内获得了 50k 行的数据,但我的语料库更大,有数百万行。有没有办法以更有效的方式存储和搜索单词对?矩阵可能会工作得更快,但我的独特字数约为 300.000 字。这意味着我必须创建一个以整数作为数据类型的 300k*300k 矩阵。即使利用了对称矩阵,它也需要很多比我拥有的更多的内存。
我尝试使用 numpy 中的 memmap 将矩阵存储在磁盘而不是内存中,但它需要大约 500 GB 的可用磁盘空间。
然后我研究了稀疏矩阵,发现我可以只存储非零值及其对应的行号和列号。这是我在代码中所做的。
目前,该模型有效,但在正确猜测下一个单词方面非常糟糕(大约 8% 的成功率)。我需要用更大的语料库训练以获得更好的结果。我该怎么做才能让这个词对查找代码更有效率?
谢谢。
编辑:感谢大家的回答,我现在能够在大约 15 秒内处理我的约 500k 行语料库。我正在为有类似问题的人添加以下代码的最终版本:
import numpy as np
import time
start = time.time()
myDict = {} # empty dict
with open("markovData.txt") as f:
contentData = f.readlines()
contentData = [x.strip() for x in contentData]
lineIndex = 0
for line in contentData:
tmpArray = line.split() #split line to array of words
tmpArrayIndex = 0
for tmpArrayIndex in range(len(tmpArray) - 1): #do this for every word except the last one since the last word has no word after it.
if (tmpArray[tmpArrayIndex], tmpArray[tmpArrayIndex + 1]) in myDict: #if the word pair is was seen before
myDict[tmpArray[tmpArrayIndex], tmpArray[tmpArrayIndex + 1]] += 1 #increment the frequency of said pair
else:
myDict[tmpArray[tmpArrayIndex], tmpArray[tmpArrayIndex + 1]] = 1 #if the word pair is never seen before
#add the pair to list and set frequency to 1.
#print every 1000th line to check the progress
lineIndex += 1
if ((lineIndex % 1000) == 0):
print(lineIndex)
end = time.time()
print(end - start)
keyText= ""
valueText = ""
for key1,key2 in myDict:
keyText += (str(key1) + "," + str(key2) + " ")
valueText += (str(myDict[key1,key2]) + " ")
with open("markovPairs.txt", 'a', encoding="utf8") as markovPairsFile:
markovPairsFile.write(keyText)
with open("markovFrequency.txt", 'a', encoding="utf8") as markovFrequencyFile:
markovFrequencyFile.write(valueText)
【问题讨论】:
-
您可以尝试使用平面字典,而不是使用列表列表,其中键是附加的单词 ids K;L。我假设对于大多数单词,它们不会配对。然后,您可以简单地增加 mydict[K;L] = mydict[K;L] + 1,而不是检查你之前是否见过一个词对 K,L(这是你现在算法的瓶颈)。
-
另外,您正在一次又一次地写入文件。相反,将字符串连接一次并将其写入文件一次。参考这个答案:stackoverflow.com/a/27384379/1176596。这实际上是我认为更大的瓶颈。
标签: python performance nlp processing-efficiency