L'une des tâches de la PNL est la classification des documents. Il évalue l'étiquette d'un document étiqueté.
La classification des documents peut être largement divisée en deux types suivant la nature de l'étiquette attachée au document.
--Classification thématique --Documents étiquetés sur le sujet
--Analyse des sentiments
Il existe de nombreuses façons de résoudre ces problèmes de classification de documents. Il existe les deux méthodes typiques suivantes. (Je pense qu'il y en a d'autres)
--Créez un vecteur de document et classez-le par méthode d'apprentissage automatique --Comment créer un vecteur de document - Tf-idf --bag d'incorporation (prend la moyenne ou le maximum pour la représentation distribuée de chaque mot dans le document) --Comment classer - Logistic Regression - Naive Baise model - Support Vector Machine - Random Forest, Xgboost --Etc
--Placer le texte de la ligne dans un réseau neuronal - LSTM - BERT fine tuning --Etc
Même si j'ai fait le plus simple, je ne sais pas vraiment lequel est le plus facile (hé). Cette fois, je voudrais travailler sur la méthode de SVM (avec karnel linéaire) le vecteur Tf-idf. Tf-idf est un vecteur dont la fréquence d'occurrence de chaque mot dans un document est multipliée par l'importance de ce mot en tant qu'élément. Par conséquent, la dimension du vecteur de document est égale au nombre de vocabulaire.
SVM avec karnel linéaire semble être un peu difficile à expliquer, donc je vais l'omettre.
Cette fois, j'utiliserai celui inclus dans sklearn.
Le modèle étant simple (?), Je vais essayer d'utiliser un corpus un peu compliqué (multi-étiquettes + quelques rubriques sont données à chaque document). Le corpus utilisé est un article de presse de Reuters avec environ 10 000 documents et 90 étiquettes.
Téléchargez le corpus. Le corpus reuters est inclus dans le module python nltk, alors utilisez-le.
Premièrement, si nltk n'est pas inclus
pip install nltk
Tapez ensuite ce qui suit dans le shell interactif de python:
python
>>> import nltk
>>> nltk.download("reuters")
Ensuite, un répertoire appelé nltk_data est créé sous le répertoire utilisateur et les données se trouvent dans ce répertoire. ____ Est à l'intérieur.
import glob
import nltk
import re
import codecs
from sklearn.feature_extraction.text import TfidfVectorizer
from nltk import word_tokenize
from nltk.stem.porter import PorterStemmer
from nltk.corpus import stopwords, reuters
from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.svm import SVC
from sklearn.multiclass import OneVsRestClassifier
from sklearn import metrics
path = "../nltk_data/corpora/reuters/"
with open(path+"stopwords") as sw:
stopwords = [x for x in sw]
#Définir le tokenizer
def tokenize(text):
min_length = 3
words = map(lambda word: word.lower(), word_tokenize(text))
words = [word for word in words if word not in stopwords]
tokens = (list(map(lambda token: PorterStemmer().stem(token), words)))
p = re.compile('[a-zA-Z]+');
filtered_tokens = list(filter (lambda token: p.match(token) and len(token) >= min_length, tokens))
return filtered_tokens
#Obtenir l'identifiant du document et sa catégorie à partir des données
with codecs.open("../nltk_data/corpora/reuters/cats.txt", "r", "utf-8", "ignore") as categories:
train_docs_id = [line.split(" ")[0][9:] for line in categories if line.split(" ")[0][:9] == 'training/']
categories.seek(0)
test_docs_id = [line.split(" ")[0][5:] for line in categories if line.split(" ")[0][:5] == 'test/']
categories.seek(0)
train_docs_cat = [line.strip("\n").split(" ")[1:] for line in categories if line.split(" ")[0][:9] == 'training/']
categories.seek(0)
test_docs_cat = [line.strip("\n").split(" ")[1:] for line in categories if line.split(" ")[0][:5] == 'test/']
#Lister les documents
train_docs = []
test_docs = []
for num in train_docs_id:
with codecs.open(path+"training/"+num, "r", "utf-8", "ignore") as doc:
train_docs.append(" ".join([line.strip(" ") for line in doc.read().split("\n")]))
for num in test_docs_id:
with codecs.open(path+"test/"+num, "r", "utf-8", "ignore") as doc:
test_docs.append(" ".join([line.strip(" ") for line in doc.read().split("\n")]))
#Sklearn à partir de la liste des documents.Générer un vecteur de document avec TfidfVectorizer
vectorizer = TfidfVectorizer(tokenizer=tokenize)
vectorised_train_documents = vectorizer.fit_transform(train_docs)
vectorised_test_documents = vectorizer.transform(test_docs)
#Étiquette binaire(0 or 1)Convertir en un vecteur de
# Transform multilabel labels
mlb = MultiLabelBinarizer()
train_labels = mlb.fit_transform(train_docs_cat)
test_labels = mlb.transform(test_docs_cat)
# Classifier
#Essayez différents paramètres
param_list = [0.001, 0.01, 0.1, 0.5, 1, 10, 100]
for C in param_list:
classifier = OneVsRestClassifier(LinearSVC(C=C, random_state=42))
classifier.fit(vectorised_train_documents, train_labels)
predictions = classifier.predict(vectorised_test_documents)
train_predictions = classifier.predict(vectorised_train_documents)
ftest = metrics.f1_score(test_labels, predictions, average="macro")
ftrain = metrics.f1_score(train_labels, train_predictions, average="macro")
print("parameter test_f1 train_f1")
print("c={}:\t{}\t{}".format(C, ftest, ftrain))
L'exécution du code ci-dessus donne le résultat suivant:
parameter test_f1 train_f1
c=0.001: 0.009727246626471432 0.007884179312750742
c=0.01: 0.02568945815128711 0.02531440097069285
c=0.1: 0.20504347026711428 0.26430270726815386
c=0.5: 0.3908058642922242 0.6699048987962078
c=1: 0.45945765878179573 0.9605946547451458
c=10: 0.5253686991407462 0.9946632502765812
c=100: 0.5312185383446876 0.9949908225328556
Vous apprenez à votre guise. La même méthode selon l'article ci-dessous devrait donner une précision de la seconde moitié de 80% ... https://www.aclweb.org/anthology/N19-1408/
Si quelqu'un sait pourquoi ce n'est pas bon, faites-le moi savoir.
Recommended Posts