Нормализация на корпусе с использованием словаря - PullRequest
0 голосов
/ 25 марта 2020

Я хочу выполнить лексическую нормализацию в корпусе, используя словарь. В корпусе восемь тысяч строк, а в словаре тысячи пар слов (нестандартный: стандартный).

Я принял подход, который обсуждается здесь . Код выглядит следующим образом:

with open("corpus.txt", 'r', encoding='utf8') as main:
    words = main.read().split()

lexnorm = {'nonstandard1': 'standard1', 'nonstandard2': 'standard2', 'nonstandard3': 'standard3', and so on}

for x in lexnorm:
    for y in words:
        if lexnorm[x][0] == y:
            y == x[1]

text = ' '.join(lexnorm.get(y, y) for y in words)

print(text)

Код выше работает хорошо, но я столкнулся с проблемой, поскольку в словаре тысячи пар слов. Можно ли представить словарь через текстовый файл?

Последний вопрос, выходной файл кода состоит только из одной строки. Было бы здорово, если бы в нем было столько же строк, сколько в оригинальном корпусе.

Кто-нибудь может мне помочь с этим? Я был бы благодарен.

1 Ответ

1 голос
/ 25 марта 2020

Одним из способов вывода словаря в виде текстового файла является строка JSON:

import json

lexnorm = {'nonstandard1': 'standard1', 'nonstandard2': 'standard2', 'nonstandard3': 'standard3'} # etc.

with open('lexnorm.txt', 'w') as f:
    json.dump(lexnorm, f)

Смотрите мой комментарий к вашему оригиналу. Я только догадываюсь, что вы пытаетесь сделать:

import json, re

with open('lexnorm.txt') as f:
    lexnorm = json.load(f) # read back lexnorm dictionary

with open("corpus.txt", 'r', encoding='utf8') as main, open('new_corpus.txt', 'w') as new_main:
    for line in main:
        words = re.split(r'[^a-zA-z]+', line)
        for word in words:
            if word in lexnorm:
                line = line.replace(word, lexnorm[word])
        new_main.write(line)

Вышеупомянутая программа построчно читает файл corpus.txt и пытается интеллектуально разбить строку на слова. Разделение на одно пространство не является адекватным. Рассмотрим следующее предложение:

'"The fox\'s foot grazed the sleeping dog, waking it."'

Стандартное разбиение на один пробел дает:

['"The', "fox's", 'foot', 'grazed', 'the', 'sleeping', 'dog,', 'waking', 'it."']

Вы никогда не сможете найти совпадения The, fox, dog ни it.

Есть несколько способов справиться с этим. Я делю на один или несколько не-буквенных символов. Это может потребоваться «настроить», если слова в lexnorm состоят из символов, отличных от az:

re.split(r'[^a-zA-z]+',  '"The fox\'s foot grazed the sleeping dog, waking it."')

Выход:

['', 'The', 'fox', 's', 'foot', 'grazed', 'the', 'sleeping', 'dog', 'waking', 'it', '']

Как только строка разбита на слова, каждое слово ищется в словаре lexnorm, и, если оно найдено, выполняется простая замена этого слова в исходной строке. Наконец, строка и любые замены, сделанные для этой строки, записываются в новый файл. Затем вы можете удалить старый файл и переименовать новый.

Подумайте, как вы можете обработать слова, которые будут соответствовать, если бы они были сначала преобразованы в нижний регистр.

Обновить ( Основная оптимизация)

Поскольку в файле может быть много повторяющихся слов, оптимизация заключается в том, чтобы обрабатывать каждое уникальное слово один раз, что можно сделать, если файл не настолько большой, что он невозможно прочитать в память:

import json, re

with open('lexnorm.txt') as f:
    lexnorm = json.load(f) # read back lexnorm dictionary

with open("corpus.txt", 'r', encoding='utf8') as main:
    text = main.read()
word_set = set(re.split(r'[^a-zA-z]+', text))
for word in word_set:
    if word in lexnorm:
        text = text.replace(word, lexnorm[word])
with open("corpus.txt", 'w', encoding='utf8') as main:
    main.write(text)

Здесь весь файл считывается в text, разбивается на слова, а затем слова добавляются в набор word_set, гарантирующий уникальность слов. Затем каждое слово в word_set ищется и заменяется во всем тексте, а весь текст перезаписывается обратно в исходный файл.

...