#!/usr/bin/env python
# coding: utf-8
#
#
# Методы машинного обучения
# Введение в NLP
# In[1]:
get_ipython().run_line_magic('matplotlib', 'inline')
# In[2]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (12,8)
# # Работа с текстом
# Рассмотрим коллекцию новостных сообщений за первую половину 2017 года. Про каждое новостное сообщение известны:
# * его заголовок и текст
# * дата его публикации
# * событие, о котором это новостное сообщение написано
# * его рубрика
# In[3]:
df = pd.read_csv('./data/news.csv', encoding='utf8')
df.head()
# In[9]:
print(df.text[0])
# In[4]:
df.shape
# In[7]:
df.loc[:, 'class'].value_counts()
# In[5]:
df.event.value_counts()
# ## Токенизация
#
# Используем регулярные выражения, чтобы разбить тексты на слова
# In[10]:
import re
regex = re.compile(u"[А-Яа-я]+")
def words_only(text, regex=regex):
return " ".join(regex.findall(text))
df.text = df.text.str.lower()
df.loc[:, 'text'] = df.text.apply(words_only)
# Результат:
# In[11]:
print(df.text.iloc[0])
# ### Самые частые слова
# In[12]:
from nltk import FreqDist
n_types = []
n_tokens = []
tokens = []
fd = FreqDist()
for index, row in df.iterrows():
tokens = row['text'].split()
fd.update(tokens)
n_types.append(len(fd))
n_tokens.append(sum(fd.values()))
for i in fd.most_common(10):
print(u'{}: {}'.format(i[0], i[1]))
# ## Обработка текстов
#
#
# ### Удаление стоп-слов
# In[13]:
import nltk
# In[15]:
# nltk.download()
# In[19]:
from nltk.corpus import stopwords
mystopwords = stopwords.words('russian') + ['это', 'наш' , 'тыс', 'млн', 'млрд', u'также', 'т', 'д', '-', '-']
print(mystopwords)
def remove_stopwords(text, mystopwords = mystopwords):
try:
return u" ".join([token for token in text.split() if not token in mystopwords])
except:
return u""
df.text = df.text.apply(remove_stopwords)
# In[21]:
df.text[0]
# ### Лемматизация
# In[23]:
get_ipython().system('pip install pymystem3')
# In[27]:
get_ipython().system('pip install pymorphy2')
get_ipython().system('pip install -U pymorphy2-dicts-ru')
get_ipython().system('pip install -U pymorphy2-dicts-uk')
# In[28]:
import pymorphy2
# In[32]:
m = pymorphy2.MorphAnalyzer()
m.normal_forms('митинги')
def lemmatize(text, mystem=m):
try:
return " ".join(m.normal_forms(word)[0] for word in text.split(' '))
except:
return " "
df.loc[:, 'text_morphy'] = df.text.apply(lemmatize)
# In[33]:
df.loc[0, 'text_morphy']
# In[24]:
get_ipython().run_cell_magic('time', '', 'from pymystem3 import Mystem\n\nm = Mystem()\ndef lemmatize(text, mystem=m):\n try:\n return "".join(m.lemmatize(text)).strip() \n except:\n return " "\n\ndf.text = df.text.apply(lemmatize)\n')
# In[26]:
df.text[0]
# ### Удаление стоп-лемм
# In[34]:
mystoplemmas = [u'который', u'прошлый', u'сей', u'свой', u'наш', u'мочь']
def remove_stoplemmas(text, mystoplemmas = mystoplemmas):
try:
return " ".join([token for token in text.split() if not token in mystoplemmas])
except:
return ""
df.text = df.text.apply(remove_stoplemmas)
# In[35]:
df.text.head()
# Самые частые леммы:
# In[36]:
lemmata = []
for index, row in df.iterrows():
lemmata += row['text'].split()
fd = FreqDist(lemmata)
for i in fd.most_common(10):
print(u'{}: {}'.format(i[0], i[1]))
# ## Извлечение ключевых слов
# ## N-граммы (n-grams)
# * $w_1$, $w_2$ - слова
# * $p(w_1)$, $p(w_2)$ - частоты слов
# * $p(w_1, w_2)$ - частота биграммы
#
#
# * $PMI(w_1, w_2) = \log\frac{p(w_1, w_2)}{p(w_1)p(w_2)}$
# * $\text{T-score}(w_1, w_2) = \frac{p(w_1,w_2) - p(w_1)p(w_2)}{p(w_1, w_2)/N}$
# * ...
# Переезжаем из DataFrame в списки:
# In[37]:
tokens_by_topic = []
for event in df.event.unique():
tokens = []
sample = df[df.event==event]
for i in range(len(sample)):
tokens += sample.text.iloc[i].split()
tokens_by_topic.append(tokens)
# Выберем событие, из текстов про которое будем извлекать ключевые слова:
# In[40]:
event_id = 3
# Извлекаем биграммы по разным мерам связности:
# In[41]:
get_ipython().run_cell_magic('time', '', "import nltk\nfrom nltk.collocations import *\nN_best = 100 # число извлекаемых биграм\n\nbigram_measures = nltk.collocations.BigramAssocMeasures() # класс для мер ассоциации биграм\nfinder = BigramCollocationFinder.from_words(tokens_by_topic[event_id]) # класс для хранения и извлечения биграм\nfinder.apply_freq_filter(3) # избавимся от биграм, которые встречаются реже трех раз\nraw_freq_ranking = [' '.join(i) for i in finder.nbest(bigram_measures.raw_freq, N_best)] # выбираем топ-10 биграм по частоте \ntscore_ranking = [' '.join(i) for i in finder.nbest(bigram_measures.student_t, N_best)] # выбираем топ-10 биграм по каждой мере \npmi_ranking = [' '.join(i) for i in finder.nbest(bigram_measures.pmi, N_best)]\nchi2_ranking = [' '.join(i) for i in finder.nbest(bigram_measures.chi_sq, N_best)]\n")
# Результаты:
# In[42]:
rankings = pd.DataFrame({ 'chi2': chi2_ranking, 't-score' : tscore_ranking, 'pmi': pmi_ranking, 'raw_freq':raw_freq_ranking})
rankings = rankings[['raw_freq', 'pmi', 't-score', 'chi2', ]]
rankings.head(10)
# In[45]:
'дмитрий_медведев'
# ## Вычисление сходства
# С помощью `TfidfVectorizer` и `pairwise_distances` расчитайте косинусное расстояние между всеми парами документов к корпусе
#
# Запишите результат в переменную `S`
# In[46]:
import seaborn as sns
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import pairwise_distances
# In[47]:
vect = TfidfVectorizer()
# In[48]:
texts = df.text.values
X = vect.fit_transform(texts)
# In[50]:
sims = pairwise_distances(X, metric='cosine')
# In[52]:
sims.shape
# In[53]:
plt.figure(figsize = (10,10))
sns.heatmap(data=sims, cmap = 'Spectral').set(xticklabels=[],yticklabels=[])
# ### FYI тоже самое в Gensim
# In[ ]:
get_ipython().system('pip install gensim')
# In[54]:
from gensim.corpora import *
texts = [df.text.iloc[i].split() for i in range(len(df))]
dictionary = Dictionary(texts)
corpus = [dictionary.doc2bow(text) for text in texts]
# In[55]:
from gensim.models import *
tfidf = TfidfModel(corpus)
corpus_tfidf = tfidf[corpus]
# In[56]:
from gensim import similarities
index = similarities.MatrixSimilarity(corpus_tfidf)
sims = index[corpus_tfidf]
# In[57]:
plt.figure(figsize = (10,10))
sns.heatmap(data=sims, cmap = 'Spectral').set(xticklabels=[],yticklabels=[])
# # LSA
# C помощью `TruncatedSVD` выполните LSА преобразование документов
# In[58]:
from sklearn.decomposition import TruncatedSVD
# In[59]:
lsa = TruncatedSVD(n_components=10, random_state=123)
Z = lsa.fit_transform(X)
# In[61]:
X.shape
# In[60]:
Z.shape
# In[63]:
Z[:5]
# In[65]:
from sklearn.preprocessing import LabelEncoder
# In[66]:
enc = LabelEncoder()
# In[68]:
df.loc[:, 'class'].value_counts()
# In[69]:
label = enc.fit_transform(df.loc[:, 'class'])
# In[70]:
plt.scatter(Z[:,0], Z[:,1], c=label)
# Так же посчитайте косинусное расстояние и визуализируйте его
# In[71]:
sims = pairwise_distances(Z, metric='cosine')
# In[72]:
sims.shape
# In[73]:
plt.figure(figsize = (10,10))
sns.heatmap(data=sims, cmap = 'Spectral').set(xticklabels=[],yticklabels=[])
# Составьте некоторый "поисковый запрос" и найдите наиболее подходящие документы из корпуса с помощью LSI
# In[119]:
q = u'премьер министр великобритании'
q_norm = lemmatize(q)
# In[120]:
q_norm
# In[121]:
q_bow = vect.transform([q_norm])
# In[122]:
q_lsa = lsa.transform(q_bow)
# In[123]:
sims = pairwise_distances(Z, q_lsa, metric='cosine')
# In[124]:
idx = np.argsort(sims, axis=0)[:,0]
# In[125]:
df.iloc[idx, 0]
# ### FYI тоже самое в Gensim
%%time
lsi = lsimodel.LsiModel(corpus=corpus_tfidf,
id2word=dictionary,
num_topics=50)topics = lsi.show_topics()for t in range(5):
print('=====')
print(topics[t][1])corpus_lsi = lsi[corpus]
index = similarities.MatrixSimilarity(lsi[corpus])
sims = index[corpus_lsi]
sims = (sims + 1)/2.quert = u"поисковый запрос"
vec_bow = dictionary.doc2bow(doc.lower().split())
vec_lsi = lsi[vec_bow] # convert the query to LSI spacesims = index[vec_lsi]
print(list(enumerate(sims))) # print (document_number, document_similarity) 2-tuples