В начало > Первичная обработка текста
При анализе естественного языка часто приходится сталкиваться с задачей предварительной обработки текстов. Для того, чтобы начать работу с текстовой информацией, нужно ее нужно почистить, убрать ненужное. Здесь приводится простая процедура на Python'е, которую я использую для первичной чистки данных.
Предположим, у нас есть задача - посчитать частоты слов и знаков пунктуации в некотором наборе текстов. Первое, что необходимо сделать - определить допустимый алфавит. В нашем случае просто зададим его регулярным выражением. Далее, необходимо пройтись по тексту и отобрать нужные блоки (слова). Приблизительно, так:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
from collections import defaultdict
r_alphabet = re.compile(u'[а-яА-Я0-9-]+|[.,:;?!]+')
def count(corpus):
tokens = defaultdict(lambda: 0)
for line in open(corpus):
line = line.decode('utf-8').lower()
for token in r_alphabet.findall(line):
tokens[token] += 1
return tokens
tokens = count('corpus.txt')
Здесь defaultdict используется для подсчета частоты встречаемых слов. Это словарь, дефолтные значение которого определяется функцией. В данном случае, дефолтное значение - 'lambda: 0'. Довольно распространенный прием для подобного рода задач. В итоге, функция count возвращает словарь токенов в виде пар (слово, частота).
Есть еще один прием, эквивалентный первому. Он использует метод split скомпилированного выражения.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
from collections import defaultdict
r_alphabet = re.compile(u'[а-яА-Я0-9-.,:;?!]+')
r_punct = re.compile(u'([.,:;?!]+)')
def count(corpus):
tokens = defaultdict(lambda: 0)
data = open(corpus)
for line in data:
line = line.decode('utf-8').lower()
for chunk in r_alphabet.findall(line):
for token in r_punct.split(chunk):
if token:
tokens[token] += 1
return tokens
tokens = count('corpus.txt')
Здесь r_punct - список знаков пунктуации. Для "очищения" слов от лишних символов используем метод split скомпилированного регулярного выражения. Значение регулярного выражения помещено в скобки затем, что нам интересно получить также и знаки препинания: '?слово...' -> ['?', 'слово', ','].
В итоге, получим очищенный набор слов. На моем корпусе, в первой десятке:
,: 312282 .: 200092 и: 89792 в: 70790 не: 50108 ... снова: 1598 всегда: 1593 свою: 1584 совсем: 1578Этим методом я пользуюсь, если необходимо провести простую обработку (токенизацию) текста. Просто и эффективно.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
from collections import defaultdict
r_alphabet = re.compile(u'[а-яА-Я0-9-]+|[.,:;?!]+')
def gen_lines(corpus):
data = open(corpus)
for line in data:
yield line.decode('utf-8').lower()
def gen_tokens(lines):
for line in lines:
for token in r_alphabet.findall(line):
yield token
def count(corpus):
tokens = defaultdict(lambda: 0)
lines = gen_lines(corpus)
tokens_ = gen_tokens(lines)
for token in tokens_:
tokens[token] += 1
return tokens
tokens = count('corpus.txt')
Здесь больше кода и нет выигрыша по производительности. Однако, у этого метода есть преимущество. Этот способ разделяет правила обработки строк текста, создавая своего рода конвейер. Если нам потребуется дополнительная обработка, мы просто вписываем новое правило.
Модуль re имеет один полезный, хотя и недокументированный класс re.Scanner. Этот класс позволяет провести простую токенизацию текста, т.е. преобразовать входящую последовательность символов текста в последовательность токенов (т.е. тех элементов текста, которые нам важны для дальнейшей работы).
Например, нам необходимо выделить из текста слова английского и русского языков, а также знаки препинания. При этом нам необходимо отбросить все лишние символы. Следующий код реализует данный обработчик.
# -*- encoding: utf-8 -*-
import re
def en_word(scanner, token): return 'RU_W', token
def ru_word(scanner, token): return 'EN_W', token
def punct(scanner, token): return 'PUNCT', token
scanner = re.Scanner([
(u'[a-zA-Z]+', en_word),
(u'[а-яА-Я]+', ru_word),
(u'[.,!?:;()-]+', punct),
(u'.', None) # Other
])
tokens, remainder = scanner.scan(u'Токенизация (tokenization) - это процесс преобразования текста в последовательность токенов.')
for token, value in tokens:
print token, ' ', value
На выходе получаем следующую последовательность токенов.
EN_W Токенизация
PUNCT (
RU_W tokenization
PUNCT )
PUNCT -
EN_W это
EN_W процесс
EN_W преобразования
EN_W текста
EN_W в
EN_W последовательность
EN_W токенов
PUNCT .
Этот подход интересен тем, что на выходе мы получаем классифицированную последовательность слов (символов) языка. Если далее, к примеру, нам потребуется получить морфологическую информацию этих слов, мы можем "скармливать" их соответственно русскому и английскому анализатору.