Классификация текста — это задача, в которой используется машинное обучение для классификации предложений без участия человека.
В этой работе я пытаюсь выполнить задачу быстрой классификации текста в наборе данных на турецком языке. Набор данных был огромным, поэтому мой компьютер не мог его обработать, поэтому я взял только 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