Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Вступление в обзор текстовой информации с поддержкой Python и способов машинного обучения

Anna | 15.06.2014 | нет комментариев

Вступление

Сегодня я продолжу рассказ о использовании способов обзора данных и машинного обучения на утилитарных примерах. В прошлой статье мы с вами разбирались с задачей кредитного скоринга. Ниже я попытаюсь продемонстрировать решение иной задачи с того же турнира, а именно «Задачи о паспортах» (Задание №2).
При решении будут показаны основы обзора текстовой информации, а также ее кодирование для построения модели с поддержкой Python и модулей для обзора данных (pandasscikit-learnpymorphy).

Постановка задачи

При работе с огромным объёмом данных значимо поддерживать их чистоту. А при заполнении заявки на банковский продукт нужно указывать полные паспортные данные, в том числе и поле «кем выдан паспорт», число разных вариантов написаний одного и того же отделения потенциальными заказчиками может добиваться нескольких сотен. Значимо понимать, не ошибся ли заказчик, заполняя другие поля: «код подразделения», «серию/номер паспорта». Для этого нужно сверять «код подразделения» и «кем выдан паспорт».
Задача заключается в том, Дабы проставить коды подразделений для записей из тестовой выборки, базируясь на обучающей выборке.

Заблаговременная обработка данных

Загрузим данные и посмотрим, что мы имеем:

from pandas import read_csv
import pymorphy2
from sklearn.feature_extraction.text import HashingVectorizer
from sklearn.cross_validation import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, roc_auc_score
from sklearn.decomposition import PCA

train = read_csv('https://static.tcsbank.ru/documents/olymp/passport_training_set.csv',';', index_col='id' ,encoding='cp1251')
train.head(5)
passport_div_code passport_issuer_name passport_issue_month/year
id
1 422008 БЕЛОВСКИМ УВД КЕМЕРОВСКОЙ ОБЛАСТИ 11M2001
2 500112 ТП №2 В ГОР. ОРЕХОВО-ЗУЕВО ОУФМС РОССИИ ПО МО … 03M2009
3 642001 ВОЛЖСКИМ РОВД ГОР.САРАТОВА 04M2002
4 162004 УВД МОСКОВСКОГО РАЙОНА Г.КАЗАНЬ 12M2002
5 80001 ОТДЕЛОМ ОФМС РОССИИ ПО РЕСП КАЛМЫКИЯ В Г ЭЛИСТА 08M2009

Сейчас дозволено посмотреть как пользователи записывают поле «кем выдан паспорт» на примере какого-либо подразделения:

example_code = train.passport_div_code[train.passport_div_code.duplicated()].values[0]
for i in train.passport_issuer_name[train.passport_div_code == example_code].drop_duplicates():
    print i

ОТДЕЛЕНИЕМ УФМС РОССИИ ПО РЕСПУБЛИКЕ КАРЕЛИЯ В МЕДВЕЖ. Р-Е
ОТДЕЛЕНИЕМ УФМС РОССИИ ПО Р. КАРЕЛИЯ В МЕДВЕЖЬЕГОРСКОМ РАЙОНЕ
ОТДЕЛЕНИЕМ УФМС РОССИИ ПО РЕСП КАРЕЛИЯ В МЕДВЕЖЬЕГОРСКОМ Р-НЕ
ОТДЕЛЕНИЕМ УФМС РОССИИ ПО РЕСПУБЛИКЕ КАРЕЛИЯ В МЕДВЕЖЬЕГОРСКОМ РАЙОНЕ
ОУФМС РОССИИ ПО РЕСПУБЛИКЕ КАРЕЛИЯ В МЕДВЕЖЬЕГОРСКОМ РАЙОНЕ
УФМС РОССИИ ПО РК В МЕДВЕЖЬЕГОРСКОМ РАЙОНЕ
ОТДЕЛЕНИЕМ УФМС РОССИИ ПО РЕСПУБЛИКЕ КАРЕЛИЯ МЕДВЕЖЬЕГОРСКОМ Р-ОНЕ
ОТДЕЛЕНИЕМ УФМС РОССИИ ПО РК В МЕДВЕЖЬЕГОРСКОМ РАЙОНЕ
ОТДЕЛЕНИЕМ УФМС РОССИИ ПО РЕСПУБЛИКЕ КОРЕЛИЯ В МЕДВЕЖИГОРСКОМ РАЙОНЕ
УФМС РОССадминистративный округ’, u’юао’: u’южный административный округ’, u’юзао’: u’юго-западный округ’, u’ювао’: u’юго-восточный округ’, u’свао’: u’северо-восточный округ’, u’сзао’: u’северо-западный округ’, u’оуфмс’: u’отдел управление федеральной миграционной службы’, u’офмс’: u’отдел федеральной миграционной службы’, u’уфмс’: u’управление федеральной миграционной службы’, u’увд’: u’управление внутренних дел’, u’ровд’: u’региональный отдел внутренних дел’, u’говд’: u’городской отдел внутренних дел’, u’рувд’: u’районное управление внутренних дел’, u’овд’: u’отдел внутренних дел’, u’оувд’: u’отдел управления внутренних дел’, u’мро’: u’межрайонный отдел’, u’пс’: u’паспортный стол’, u’тп’: u’региональный пункт’}

Сейчас, собственно произведем расшифровку абривеатур и отформатируем полученные записи:

for i in sokr.iterkeys():
    train.passport_issuer_name = train.passport_issuer_name.str.replace(u'( %s )|(^%s)|(%s$)' % (i,i,i), u' %s ' % (sokr[i]))

#удалим лишние пробелы в конце и начале строки
train.passport_issuer_name = train.passport_issuer_name.str.lstrip()
train.passport_issuer_name = train.passport_issuer_name.str.rstrip()

Заблаговременный этап обработки поля «кем выдан паспорт» на этом завершим. И перейдем к полю, в котором находится дата выдачи.
Как дозволено подметить данные в нем хранятся в виде: месяцMгод.
Соответственно дозволено легко убрать букву «M» и привести поле к числовому типу. Но если отлично подумать, то это поле дозволено удалить, т.к. на один месяц в году может доводиться несколько подразделений выдававших паспорт, и соответственно это может испортить нашу модель. Исходя из этого удалим его из выборки:

train = train.drop(['passport_issue_month/year'], axis=1)

Сейчас мы можем перейти к обзору данных.

Обзор данных

Выходит, данные для построения модели у нас есть, но они находятся в текстовом виде. Для построения модели отлично бы было их закодировать в числовом виде.
Авторы пакета scikit-learn рачительно о нас позаботились и добавили несколько методов для извлечения и кодирования текстовых данных. Из них мне огромнее каждого нравятся два:

  1. FeatureHasher
  2. CountVectorizer
  3. HashingVectorizer

FeatureHasher преобразовывает строку в числовой массив заданной длинной с поддержкой хэш-функции (32-разрядная версия Murmurhash3)
CountVectorizer преобразовывает входной текст в матрцицу, значениями которой, являются числа вступления данного ключа(слова) в текст. В различие от FeatureHasher имеет огромнее настраиваемых параметров(скажем дозволено задать токенизатор), но работает неторопливей.
Для больше точного понимания работы CountVectorizer приведем примитивный пример. Возможен есть таблица с текстовыми значениями:

Значение
раз два три
три четыре два два
раз раз раз четыре

Для начала CountVectorizer собирает уникальные ключи из всех записей, в нашем примере это будет:

[раз, два, три, четыре]

Длина списка из уникальных ключей и будет длиной нашего закодированного текста (в нашем случае это 4). А номера элементов будут соответствовать, числу раз встречи данного ключа с данным номером в строке:

раз два три –> [1,1,1,0]
три четыре два два –> [0,2,1,1]

Соответственно позже кодировки, использования данного способа мы получим:

Значение
1,1,1,0
0,2,1,1
3,0,0,1

HashingVectorizer является смесью 2-х выше описанных способов. В нем дозволено и регулировать размер закодированной строки (как в FeatureHasher) и настраивать токенизатор (как в CountVectorizer). К тому же его продуктивность ближе к FeatureHasher.
Выходит, возвратимся к обзору. Если мы посмотрим по внимательнее на наш комплект данных то дозволено подметить, что есть схожие строки но записанные по различному скажем: “… республика карелия…” и “… по республике карелия…“.
Соответственно, если мы испробуем применить один из способов кодирования теперь мы получим дюже схожие значения. Такие случаем дозволено минимизировать если все слова в записи мы приведем к типичной форме.
Для этой задачи отлично подходит pymorphy либо nltk. Я буду применять 1-й, т.к. он первоначально создавался для работы с русским языком. Выходит, функция которая будет отвечать за нормализацию и очиску строки выглядит так:

def f_tokenizer(s):
    morph = pymorphy2.MorphAnalyzer()
    if type(s) == unicode:
        t = s.split(' ')
    else:
        t = s
    f = []
    for j in t:
        m = morph.parse(j.replace('.',''))
        if len(m) <> 0:
            wrd = m[0]
            if wrd.tag.POS not in ('NUMR','PREP','CONJ','PRCL','INTJ'):
                f.append(wrd.normal_form)
    return f

Функция делает следующее:

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

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

coder = HashingVectorizer(tokenizer=f_tokenizer, n_features=256)

Как дозволено подметить при создании способа помимо токенизатора мы задаем еще один параметрn_features. Через данный параметр задается длина закодированной строки (в нашем случае строка кодируется при помощи 256 столбцов). Помимо того, у HashingVectorizer есть еще одно превосходство передCountVectorizer, но сразу может исполнять нормализацию значений, что отлично для таких алгорифмов, как SVM.
Сейчас применим наш кодировщик к обучающему комплекту:

TrainNotDuble = train.drop_duplicates()
trn = coder.fit_transform(TrainNotDuble.passport_issuer_name.tolist()).toarray()

Построение модели

Для начала нам нужно задать значения для столбца, в котором будут содержаться метки классов:

target = TrainNotDuble.passport_div_code.values

Задача, которую мы решаем сегодня, принадлежит к классу задач систематизации со большинством классов. Для решения данной задачи отменнее каждого подошел алгорифм RandomForest. Остальные алгорифмы показали дюже дрянные итоги (менее 50%) следственно я решил не занимать место в статье. При желании всякий интересующийся может проверить данные итоги.
Для оценки качества систематизации будем применять число документов по которым принято верное решение, т. е.

, где P — число документов по которым классификатор принял верное решение, а N – размер обучающей выборки.
В пакете scikit-learn для этого есть функция: accuracy_score
Перед началом построения собственно модели, давайте сократим размерность с поддержкой «способа основных компонент», т.к. 256 столбцов для обучения достаточно много:

pca = PCA(n_components = 15)
trn = pca.fit_transform(trn)

Модель будет выглядеть так:

model = RandomForestClassifier(n_estimators = 100, criterion='entropy')

TRNtrain, TRNtest, TARtrain, TARtest = train_test_split(trn, target, test_size=0.4)
model.fit(TRNtrain, TARtrain)
print 'accuracy_score: ', accuracy_score(TARtest, model.predict(TRNtest))

accuracy_score: 0.6523456

Завершение

В качестве итога необходимо подметить, что полученная точность в 65% близка к угадыванию. Дабы усовершенствовать необходимо при первичной обработке обработать грамматические ошибки и разного рода описки. Данное действие также скажется позитивно и на словаре при кодировании поля, т. е. его размер уменьшиться и соответственно уменьшиться длина строки позже ее кодировки.
Помимо того этап обучения тестовой выборки опущен намеренно, т. к. в нем нет ничего особенного, помимо его приведения к надобному виду (это дозволено легко сделать взяв за основу реформирования обучающей выборки)
В статье я попытался показать наименьший список этапов по обработке текстовой информации для подачи ее алгорифмам машинного обучения. Допустимо делающим первые шаги в обзоре данных данная информация будет пригодной.

Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB