Я пытаюсь создать простую модель для предсказания следующего слова в предложении. У меня есть большой файл .txt, который содержит предложения, разделенные '\ n'. У меня также есть файл словаря, в котором перечислены все уникальные слова в моем файле .txt и уникальный идентификатор. Я использовал файл словаря, чтобы преобразовать слова в моем корпусе в соответствующие им идентификаторы. Теперь я хочу сделать простую модель, которая считывает идентификаторы из текстового файла и находит пары слов и сколько раз эти упомянутые пары слов были замечены в корпусе. Мне удалось написать код ниже:
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")
Этот код, кажется, работает хорошо для первых нескольких тысяч строк. Затем все становится медленнее, потому что список кортежей продолжает увеличиваться, и мне приходится искать по всему списку кортежей, чтобы проверить, была ли следующая пара слов видна раньше или нет. Мне удалось получить данные по 50 тыс. Строк за 30 минут, но у меня гораздо больше корпусов с миллионами строк. Есть ли способ хранить и искать пары слов более эффективным способом? Матрицы, вероятно, будут работать намного быстрее, но мой уникальный счетчик слов составляет около 300 000 слов. Это означает, что я должен создать матрицу 300k * 300k с целыми числами в качестве типа данных. Даже после использования симметричных матриц, потребовалось бы намного больше памяти, чем у меня.
Я пытался использовать memmap из numpy для хранения матрицы на диске, а не в памяти, но для этого требовалось около 500 ГБ свободного дискового пространства.
Затем я изучил разреженные матрицы и обнаружил, что могу просто хранить ненулевые значения и соответствующие им номера строк и столбцов. Что я и сделал в своем коде.
В настоящее время эта модель работает, но она очень плохо угадывает следующее слово (вероятность успеха около 8%). Мне нужно тренироваться с большими корпусами, чтобы получить лучшие результаты. Что я могу сделать, чтобы сделать этот код поиска пары слов более эффективным?
Спасибо.
Редактировать: Благодаря всем ответившим, теперь я могу обработать мой корпус из ~ 500k строк примерно за 15 секунд. Я добавляю финальную версию кода ниже для людей с похожими проблемами:
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)