Prelucrarea limbajului natural

5.1 Clasificarea textului

Spam sau nu? Recenzie pozitivă sau negativă? Știri sau sport? Clasificarea textului transformă cuvintele în numere, apoi aplică exact modelele din capitolul 2.

Teorie

Procesarea de text

Înainte de orice model, textul se aduce la o formă uniformă:

import re

def curata(text):
    text = text.lower()                          # litere mici
    text = re.sub(r"[^a-zăâîșț ]", " ", text)    # doar litere și spații
    text = re.sub(r"\s+", " ", text).strip()     # spații multiple
    return text

# opțional: eliminarea cuvintelor de umplutură (stop words)
stop = {"și", "de", "la", "cu", "un", "o", "în", "pe", "care", "este"}
tokens = [t for t in curata(s).split() if t not in stop]

Alte tehnici uzuale: tokenizare (spargerea în cuvinte), stemming/lematizare (reducerea la rădăcină: „alergam" → „alerg").

Bag-of-Words: textul devine vector

Construiește vocabularul tuturor cuvintelor din corpus; fiecare document devine un vector cu numărul de apariții ale fiecărui cuvânt. Ordinea cuvintelor se pierde („sacul cu cuvinte"), dar pentru clasificare tematică frecvențele sunt de obicei suficiente.

from sklearn.feature_extraction.text import CountVectorizer

texte = ["pisica bea lapte", "câinele bea apă", "pisica și câinele dorm"]
cv = CountVectorizer()
X = cv.fit_transform(texte)          # matrice rară (3 documente × vocabular)
print(cv.get_feature_names_out())    # ['apă' 'bea' 'câinele' ...]
print(X.toarray())

TF-IDF: cuvintele rare cântăresc mai mult

Problema BoW: „este", „foarte" apar peste tot și domină. TF-IDF ponderează: TF (frecvența în document) × IDF (log al rarității în corpus). Cuvintele specifice unui document primesc greutate mare; cele omniprezente, aproape zero.

from sklearn.feature_extraction.text import TfidfVectorizer

tfidf = TfidfVectorizer(
    max_features=20000,     # limitează vocabularul
    ngram_range=(1, 2),     # cuvinte singure + perechi ("foarte bun")
    min_df=2,               # ignoră cuvintele care apar o singură dată
)
X_train = tfidf.fit_transform(texte_train)   # fit doar pe train!
X_test = tfidf.transform(texte_test)

Antrenare și evaluare

Peste vectorii TF-IDF merg foarte bine modelele liniare — regresia logistică și LinearSVC sunt standardul; Naive Bayes e o alternativă rapidă. Evaluarea: acuratețe / F1 + matricea de confuzie ca să vezi ce clase se confundă (lecțiile 4.1 și 4.4).

Problemă rezolvată: clasificarea textelor în categorii tematice

Clasificarea textelor în categorii tematice Mediu Rezolvată — 100p

Fiecare text trebuie etichetat cu tema lui (sport, politică, tehnologie...). Rețeta TF-IDF + model liniar duce la 100p.

Soluția pas cu pas
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score

train = pd.read_csv("train.csv")     # coloane: text, categorie
test = pd.read_csv("test.csv")

pipe = Pipeline([
    ("tfidf", TfidfVectorizer(max_features=30000, ngram_range=(1, 2),
                              sublinear_tf=True)),
    ("clf", LogisticRegression(max_iter=2000, C=5)),
])

print(cross_val_score(pipe, train["text"], train["categorie"],
                      cv=5, scoring="f1_macro").mean().round(3))

pipe.fit(train["text"], train["categorie"])
pd.DataFrame({
    "SampleID": test["SampleID"],
    "categorie": pipe.predict(test["text"])
}).to_csv("submission.csv", index=False)

Idei pentru puncte în plus: caracter n-grams (analyzer="char_wb", ngram_range=(2,5)) — surprinzător de puternice pe română; tuning pe C; combinarea predicțiilor mai multor vectorizatoare.

Probleme propuse

1. TF-IDF de mână Exercițiu

Corpus: d1 = „pisica bea lapte", d2 = „pisica doarme", d3 = „câinele bea apă". Calculează manual TF-IDF pentru „pisica" și „lapte" în d1. Care contează mai mult și de ce?

2. Clasificarea emoțiilor pe baza textului Platformă

Aplică rețeta din problema rezolvată; compară BoW vs TF-IDF vs char n-grams.

3. Identificarea autorului unor versuri Platformă

Cine a scris strofa? Stilul se ascunde în frecvențele cuvintelor — teren perfect pentru TF-IDF.

4. Ce a învățat modelul? Exercițiu

După antrenarea regresiei logistice pe TF-IDF, afișează pentru fiecare clasă cele 10 cuvinte cu coeficienții cei mai mari. Au sens? (Aceasta e interpretarea modelului — subiect frecvent de discuție la prezentarea soluțiilor.)