Preprocessing di un testo con Python

  • Di
  • 2022-06-29 - 6 minuti
banner

Sulla base di alcune conversazioni passate, mi sono resa conto che la pre-elaborazione del testo è un argomento spesso trascurato.

La maggior parte delle persone con cui ho parlato hanno menzionato risultati incoerenti ottenuti dall’utilizzo di tecniche di NLP per poi rendersi conto che non stavano elaborando il testo per prepararlo all’analisi successiva.

Tenendo questo a mente, ho pensato di far luce su cosa sia realmente il preprocessing di un testo con Python, i diversi metodi di preelaborazione del testo e diverse tecniche che ci permettono di stimare quanto lavoro potrebbe essere necessario.

Cosa vedrai

Tutto in minuscolo

Ridurre in minuscolo tutti i dati testuali, anche se può sembrare banale, è una di quelle attività super semplici e che però portano a grandi risultati.

Pensiamo al calcolo della similarità tra più entità: il nostro programma potrebbe considerare come diverse delle parole che hanno la lettera maiuscola iniziale.

Questo tipo di typo può essere riscontrato di frequente: il set di dati potrebbe contenere diverse rappresentazioni della parola “pizza” e non avrebbe “prove” sufficienti per i suoi algoritmi di addestramento per apprendere efficacemente.

Un esempio per rendere in minuscolo una serie di parole contenute in una lista, potresti fare qualcosa di simile:

texts=["pizza","Pizza","PIZZA","PiZzA"]
lower_words=[word.lower() for word in texts]
print(lower_words)

Se volessi farlo su un dataframe?

Nulla di più semplice. Come mostrato di seguito, è sufficiente importare pandas, leggere il dataframe e iterare le colonne applicando il metodo lower() su ogni colonna. Attenzione: usiamo .str per evitare che, nel caso siano presenti dati numerici, il codice vada in errore!

import pandas as pd

data = {'Fruits': ['BANANA','APPLE','MANGO','WATERMELON','PEAR'],
        'Color': ['Yellow', 'Red', 'Orange', 'Pink', 'Green']
        }

df = pd.DataFrame(data, columns = ['Fruits', 'Color'])

print (df)

for column in df:
     df[column] = df[column].str.lower()

print(df)

>>>

	Fruits 	Color
0 	banana 	yellow
1 	apple 	red
2 	mango 	orange
3 	watermelon 	pink
4 	pear 	green

Stemming

Lo stemming è il processo di riduzione alla radice etimologica delle parole (ad es. buonissimo, buoni diventa buon). La “radice” in questo caso potrebbe non essere una vera radice, ma solo una forma canonica della parola originale.

Lo stemming utilizza un processo euristico che rimuove le estremità delle parole nella speranza di trasformarle correttamente nella loro forma radice. Quindi le parole “buonissimo” e “buoni” potrebbero effettivamente essere convertiti in buon, che non rappresenta la radice reale della parola!

Esistono diversi algoritmi per lo stemming, e spesso cambiano a seconda della lingua.

L’algoritmo più comune, noto anche per essere empiricamente efficace per l’inglese, è l’algoritmo di Porter.

Tra l’altro, il suo creatore è un signore super gentile che ho avuto l’onore di intervistare per la pubblicazione del libro “Analisi del linguaggio con Python”, edizione di Apogeo. Attualmente è in pensione, odia le macchine e le gomme da masticare e adora passare del tempo nel suo giardino (qui il suo sito).

Qui un esempio del suo funzionamento:

import nltk
import pandas as pd
from nltk.stem import PorterStemmer

porter_stemmer=PorterStemmer()

words=["trouble","troubles","troubling","troubled","troubleshooting"]
stemmed_words=[porter_stemmer.stem(word=word) for word in words]

Se abbiamo a che fare con testi non in inglese, ci sono comunque diverse opzioni: abbiamo la libreria NLTK che ci fornisce lo Snowball Stemmer, che supporta tra le altre lingue anche quella italiana:

from nltk.stem import SnowballStemmer


stemmer_snowball = SnowballStemmer('italian')


eg1 = ['andare', 'andai', 'andiamo', 'andarono']

eg_list = []

eg_list.extend(eg1)


print('Parole: {}\nRadici:'.format(eg_list))

for word in eg_list:

    print('\t- {}'.format(stemmer_snowball.stem(word)))

Parole: ['andare', 'andai', 'andiamo', 'andarono']
Radici:
	- andar
	- anda
	- andiam
	- andar

Lemmatizzazione

La lemmatizzazione sembra in apparenza molto simile allo stemming, in cui l’obiettivo è rimuovere le desinenze e ridurre una parola alla sua forma radice.

La reale differenza è che la lemmatizzazione cerca di farlo nel modo corretto. Non si limita a tagliare le parole, in realtà trasforma le parole nella radice effettiva.

Ad esempio, la parola “migliore” verrebbe associata a “buono”, e non “miglior”.

Lo fa utilizzando un dizionario come WordNet per mappare una parola con le parole collegate, ed eventualmente la sua radice, basandosi su un sistema di regole.

Per la lingua inglese, possiamo utilizzare sempre la libreria NLTK che fornisce l’oggetto WordNetLemmatizer, il quale ci permette di eseguire la lemmatizzazione su un insieme di parole:

import nltk

nltk.download('wordnet')
nltk.download('omw-1.4')
import pandas as pd
from nltk.stem import WordNetLemmatizer

lemmatizer = WordNetLemmatizer()

words = ["trouble", "troubling", "troubled", "troubles"]
lemmatized_words = [lemmatizer.lemmatize(word=word, pos='v') for word in words]
lemmatizeddf = pd.DataFrame({'original_word': words, 'lemmatized_word': lemmatized_words})
lemmatizeddf = lemmatizeddf[['original_word', 'lemmatized_word']]
print(lemmatizeddf)

Per la lingua italiana -e molte altre-, che risulta più complicata per questo tipo di attività, esiste la libreria simplelemma, sviluppata da Adrien Barbaresi, che ha un livello di accuratezza del 93%.

Un esempio è quello riportato di seguito, dove le parole ‘migliore’, ‘camminiamo’, ‘mangiassimo’, ‘promisi’ e ‘derivante’ vengono correttamente riportate al lemma:

import simplemma

mywords = ['migliore', 'camminiamo', 'mangiassimo', 'promisi', 'derivante']

langdata = simplemma.load_data('it')

result = []
for word in mywords:
    result.append(simplemma.lemmatize(word, langdata))

print(result)

Stop alle stop words!

Gioco di parole a parte, le stopwords sono un insieme di parole comunemente usate in una lingua e che quindi non danno -solitamente- alcun valore aggiunto al contesto.

Esempi di_stopwords_ in inglese sono “a”, “the”, “is”, “are” e così via, così come in italiano lo sono gli articoli, le preposizione, alcuni avverbi, e via dicendo.

L’idea alla base dell’uso di queste parole è che, rimuovendo le parole che non forniscono informazioni utili dal testo, possiamo concentrarci invece sulle parole veramente importanti.

Ad esempio, nel contesto di un sistema di ricerca, in una query di ricerca con “che cos’è il preprocessing di un testo”, vorremo che il sistema di ricerca si concentri sui risultati di pagine che parlano di preprocessing di un testo rispetto a documenti che parlano di ciò che è un testo.

Nella mia esperienza, la rimozione delle stopwords dipende dal contesto ed esistono diversi dataset adatti a diversi scopi; sebbene questa tecnica sia molto efficace nei sistemi di ricerca e di topic modeling, si è dimostrato non critico nei sistemi di classificazione.

Un esempio è quello mostrato e riportato di seguito per la lingua inglese, dove parole come this, that, of e altro vengono rimosse dal testo della frase:

stopwords=['this','that','and','a','we','it','to','is','of']
text="this is a text full of content and we need to clean it up"

words=text.split(" ")
shortlisted_words=[]

for w in words:
    if w not in stopwords:
        shortlisted_words.append(w)
    else:
        shortlisted_words.append("W")

print("original sentence = ",text)
print("sentence with stopwords removed= ",' '.join(shortlisted_words))

Se hai bisogno di un elenco di stopwords da rimuovere per diverse lingue -come italiano, spagnolo e anche ungherese-, qui trovi un repository che potrebbe fare al caso tuo!

In questa fase una delle altre tecniche di elaborazione del testo consiste nella rimozione della punteggiatura.

Ci sono circa 30+ simboli di punteggiatura principali che dovrebbero essere presi in considerazione e possiamo creare direttamente utilizzare l’oggetto_string:_ questo ha una proprietà_punctuation_ che permette di distinguere i simboli di punteggiatura.

Utilizzandolo insieme alla libreria re per le espressioni regolari, possiamo rimuovere tutti i simboli come nell’esempio di seguito:

import re
import string
testo = "Lorem, ipsum; testo! di -prova."
testo = re.sub('[%s]' % re.escape(string.punctuation), '' , testo)
print(testo)
'Lorem ipsum testo di  prova'

E tu, conosci altre tecniche? Scrivilo nei commenti!

Risorse utili

Post correlati

Partners

Community, aziende e persone che supportano attivamente il blog

Logo di Codemotion
Logo di GrUSP
Logo di Python Milano
Logo di Schrodinger Hat
Logo di Python Biella Group
Logo di Fuzzy Brains
Logo di Django Girls
Logo di Improove
Logo del libro open source
Logo di NgRome

Iscriviti alla newsletter

Per non perderti gli ultimi articoli e per vincere biglietti e gadget TheRedCode

Riceverai una volta al mese (o anche meno) gli articoli più interessanti pubblicati sul blog, e potrai provare a vincere un biglietto per uno dei prossimi eventi!

Andiamo!