Классификация текста — это задача, в которой используется машинное обучение для классификации предложений без участия человека.

В этой работе я пытаюсь выполнить задачу быстрой классификации текста в наборе данных на турецком языке. Набор данных был огромным, поэтому мой компьютер не мог его обработать, поэтому я взял только 40 тыс. строк. Это сделало мои коды быстрее. Набор данных состоит из жалоб и их классов, я не могу доказать, но они должны быть взяты с https://www.sikayetvar.com.

Я давно пробовал SGDClassifer для аналогичной задачи, поэтому моя первая модель здесь — SGDClassifer. SGDClassifer хорош для мультиклассовой классификации текста, поэтому, когда вы начинаете такую ​​задачу, я настоятельно рекомендую сначала использовать его. Кроме того, я также пробовал LinearSVC.

Библиотеки, которые необходимо импортировать:

#Mains
import numpy as np
import pandas as pd
import re
import string
#Models
from sklearn.linear_model import SGDClassifier
from sklearn.svm import LinearSVC
#Sklearn Helpers
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.metrics import classification_report
from sklearn.feature_selection import chi2
#For plots
from wordcloud import WordCloud
import matplotlib.pyplot as plt
pd.set_option(‘display.max_colwidth’, -1)

Читая набор данных, во-первых, давайте установим текстовый столбец как более низкий и удалим некоторые турецкие символы, также в конце каждого предложения есть devamını oku, что означает продолжение чтения, что означает, что предложения не сканировались идеально, и я также изменил некоторые турецкие символы. Здесь следует упомянуть, что данные содержат около 400 тыс. строк, что было слишком много для моего компьютера, поэтому я использовал только 40 тыс., но не стеснялся пробовать больше.

df=pd.read_csv(‘ticaret-yorum.csv’)
df=df.sample(n=40000, random_state=1)
df[‘text’]=df[‘text’].str.lower()
df[‘text_new’] = df[‘text’].str.replace(‘...devamını oku’, ‘’)

Давайте посмотрим, как подсчитываются значения 32 классов:

df[‘category’].value_counts().sort_index(ascending=False).plot(kind=’bar’, figsize=(12, 8))

У нас есть название бренда внутри текстового столбца, который, как я предполагаю, может вызвать переобучение, поэтому я пошел на www.şikayetvar.com и получил название бренда, чтобы исключить их из набора данных. В какой-то момент вам, возможно, придется использовать более сложные методы, чтобы найти-исключить название бренда, в качестве подсказки я могу посоветовать вам удалить все первые слова из предложений, потому что они чаще всего включают название бренда.

brands=pd.read_csv(‘https://raw.githubusercontent.com/pytmar/Jupyter-Notebooks/master/turkish_brands%20-%20Sayfa1.csv')
brands.columns=[‘brand_name’]
pat = r’\b(?:{})\b’.format(‘|’.join(list(brands[‘brand_name’].str.lower())))
df[‘text_new’] = df[‘text_new’].str.replace(pat, ‘’)
df.head(5)

Хотя модуль nltk имеет стоп-слова для турецкого языка, но он ограничен, поэтому я нашел отличный набор данных, который содержит около 1000 стоп-слов для турецкого языка, здесь я удаляю эти стоп-слова:

stop_words=pd.read_csv(‘https://raw.githubusercontent.com/InJuxSanct/turkish-stopwords/master/src/lib/stopwords/raw-stopwords.txt', sep=” “, header=None)
stop_words.columns=[‘words_list’]
pat2 = r’\b(?:{})\b’.format(‘|’.join(list(stop_words[‘words_list’].str.lower())))
df[‘text_new2’] = df[‘text_new’].str.lower().str.replace(pat2, ‘’)
df.sample(5)

Наконец удаление задачи пунктуации:

df=df.dropna()
PUNCT_TO_REMOVE = string.punctuation
def remove_punctuation(text):
 return text.translate(str.maketrans(‘’, ‘’, PUNCT_TO_REMOVE))
df[‘text_final’] = df[‘text_new2’].apply(lambda text: remove_punctuation(text)) 

Теперь давайте составим график словесного облака:

wordcloud = WordCloud(width=1000, height=500).generate(“+”.join(df[‘text_final’]))
plt.figure(figsize=(15,8))
plt.imshow(wordcloud, interpolation=’bilinear’)
plt.axis(“off”)
plt.show()

Мы также можем отобразить облако слов для определенной категории:

wordcloud = WordCloud(width=1000, height=500).generate(“+”.join(df[‘text_final’].loc[df[‘category’]==’finans’]))
plt.figure(figsize=(15,8))
plt.imshow(wordcloud, interpolation=’bilinear’)
plt.axis(“off”)
plt.show()

Разделив набор данных, вы также можете попробовать GridSearch, если ваша точность вас не удовлетворяет. Наконец, для классификации текста я предпочитаю конвейер sklearn:

X_train, X_test, y_train, y_test = train_test_split(df[‘text_final’], df[‘category’], random_state = 0)
trial = Pipeline([(‘vect’, CountVectorizer()),
 (‘tfidf’, TfidfTransformer()),
 (‘clf’, SGDClassifier()),])
parameters = {
 ‘vect__max_df’: (0.5, 0.75, 1.0),
 ‘vect__max_features’: (None, 5000, 10000, 50000),
 ‘vect__ngram_range’: ((1, 1), (1, 2)), # unigrams or bigrams
 #’tfidf__use_idf’: (True, False),
 # ‘tfidf__norm’: (‘l1’, ‘l2’),
 ‘clf__max_iter’: (20,),
 ‘clf__alpha’: (0.00001, 0.000001),
 ‘clf__penalty’: (‘l2’, ‘elasticnet’),
 # ‘clf__max_iter’: (10, 50, 80),
}
grid_search = GridSearchCV(trial, parameters, n_jobs=-1, verbose=1)
grid_search.fit(X_train, y_train)
print(“Best score: %0.3f” % grid_search.best_score_)
print(“Best parameters set:”)
best_parameters = grid_search.best_estimator_.get_params()
print(best_parameters)

Я пробовал некоторые лучшие параметры оценки, но я не нажимал сильно:

trial = Pipeline([(‘vect’, CountVectorizer(max_df=0.75, ngram_range=(1, 2))),
 (‘tfidf’, TfidfTransformer()),
 (‘clf’, SGDClassifier(loss=’modified_huber’,alpha=1e-05, max_iter=20, penalty=’elasticnet’)),])
trial.fit(X_train, y_train)
print(“Accuracy: “ + str(trial.score(X_test, y_test)))
output: Accuracy: 0.7904

LinearSVC без какой-либо настройки:

trial2 = Pipeline([(‘vectorizer’,CountVectorizer()), 
 (‘tfidf’, TfidfTransformer()),
 (‘classifier’, LinearSVC())])
trial2.fit(X_train, y_train)
print(“Accuracy: “ + str(trial2.score(X_test, y_test)))
output: Accuracy: 0.7886

Итак, теперь давайте проверим, как хорошие испытания могут предсказать, если вы хотите попробовать себя, перейдите на www.şikayetvar.com и возьмите предложение и пропустите его здесь:

SGDКлассификатор:

cv = CountVectorizer(ngram_range=(1,2))
message=”””çocuğum doğduğundan beridir Molfix bel bantlı bezi çok güzeldi, taki 3 gün önce bir eczaneden
Molfix 3 midi 6–11 kg 94 adetlik külot bez alana kadar. Aldığım bez daha 3 kez kullanımda sızdırma yapıyor
ve halen külot bez sızdırmakta devam ediyor. İçinden daha fazla bir şey kullanamadık elimizde kaldı. Öyle 
bu geri kalanı iade veya değişim yapılmasını talep ediyorum. Molfix’e hiç yakışmadı. Gerçekten sürekli bez
değiştirirken elbisede değiştirmek zorunda kalıyorduk. Normal bel bantlı bezle değiştirilirse sevinirim.”””
data = [message]
n=3
probs = trial.predict(data)
probs
output:array(['anne-bebek'], dtype='<U25')

ЛинейныйSVC:

message=”””çocuğum doğduğundan beridir Molfix bel bantlı bezi çok güzeldi, taki 3 gün önce bir eczaneden
Molfix 3 midi 6–11 kg 94 adetlik külot bez alana kadar. Aldığım bez daha 3 kez kullanımda sızdırma yapıyor
ve halen külot bez sızdırmakta devam ediyor. İçinden daha fazla bir şey kullanamadık elimizde kaldı. Öyle 
bu geri kalanı iade veya değişim yapılmasını talep ediyorum. Molfix’e hiç yakışmadı. Gerçekten sürekli bez
değiştirirken elbisede değiştirmek zorunda kalıyorduk. Normal bel bantlı bezle değiştirilirse sevinirim.”””
data = [message]
probs = trial2.predict(data)
probs
output:array(['anne-bebek'], dtype='<U25')

И вы используете прогнозирование_пробы:

message=”””çocuğum doğduğundan beridir Molfix bel bantlı bezi çok güzeldi, taki 3 gün önce bir eczaneden
Molfix 3 midi 6–11 kg 94 adetlik külot bez alana kadar. Aldığım bez daha 3 kez kullanımda sızdırma yapıyor
ve halen külot bez sızdırmakta devam ediyor. İçinden daha fazla bir şey kullanamadık elimizde kaldı. Öyle 
bu geri kalanı iade veya değişim yapılmasını talep ediyorum. Molfix’e hiç yakışmadı. Gerçekten sürekli bez
değiştirirken elbisede değiştirmek zorunda kalıyorduk. Normal bel bantlı bezle değiştirilirse sevinirim.”””
data = [message]
pd.DataFrame(sorted(zip(trial.classes_, trial.predict_proba(data)[0])), columns=[‘class’, ‘probability’]).sort_values(by=’probability’, ascending=False).head(3)
output: 

class,     probability
anne-bebek, 1.00
alisveris,  0.0
turizm,     0.0

Не забудьте проверить классификационный отчет по выступлениям классов:

y_pred=trial.predict(X_test)
print(classification_report(y_test, y_pred))

Также есть отличный способ проверить самые важные юни и биграммы для каждого класса:

df[‘category_id’]=df[‘category’].factorize()[0]
category_id_df = df[[‘text_final’, ‘category_id’]].drop_duplicates().sort_values(‘category_id’)
category_to_id = dict(category_id_df.values)
tfidf = TfidfVectorizer(sublinear_tf=True, min_df=5, norm=’l2', encoding=’latin-1', ngram_range=(1, 2))
features = tfidf.fit_transform(df.text_final).toarray()
labels = df.category_id
N = 2
for Product, category_id in sorted(category_to_id.items()):
 features_chi2 = chi2(features, labels == category_id)
 indices = np.argsort(features_chi2[0])
 feature_names = np.array(tfidf.get_feature_names())[indices]
 unigrams = [v for v in feature_names if len(v.split(‘ ‘)) == 1]
 bigrams = [v for v in feature_names if len(v.split(‘ ‘)) == 2]
 print(“# ‘{}’:”.format(Product))
 print(“ . Most correlated unigrams:\n . {}”.format(‘\n . ‘.join(unigrams[-N:])))
 print(“ . Most correlated bigrams:\n . {}”.format(‘\n . ‘.join(bigrams[-N:])))

Я не могу показать весь результат, но вот часть вывода:

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

Источники:

Данные: https://www.kaggle.com/savasy/multiclass-classification-data-for-turkish-tc32

Вдохновение: https://towardsdatascience.com/multi-label-text-classification-with-scikit-learn-30714b7819c5,

Блокнот Jupyter: https://github.com/pytmar/Jupyter-Notebooks/blob/master/medium_text_class_sklearn.ipynb