parent
369554be38
commit
819c0e4730
@ -0,0 +1,165 @@
|
|||||||
|
# Introduzione all'elaborazione del linguaggio naturale
|
||||||
|
|
||||||
|
Questa lezione copre una breve storia e concetti importanti dell' *elaborazione del linguaggio naturale*, un sottocampo della *linguistica computazionale*.
|
||||||
|
|
||||||
|
## [Quiz Pre-Lezione](https://jolly-sea-0a877260f.azurestaticapps.net/quiz/31/)
|
||||||
|
|
||||||
|
## Introduzione
|
||||||
|
|
||||||
|
NLP, come è comunemente conosciuto, è una delle aree più note in cui machine learning è stato applicato e utilizzato nei software di produzione.
|
||||||
|
|
||||||
|
✅ Si riesce a pensare a un software che si usa tutti i giorni che probabilmente ha NLP incorporato? Che dire dei programmi di elaborazione testi o le app mobili che si usano regolarmente?
|
||||||
|
|
||||||
|
Si imparerà a conoscere:
|
||||||
|
|
||||||
|
- **L'idea delle lingue**. Come si sono sviluppate le lingue e quali sono state le principali aree di studio.
|
||||||
|
- **Definizione e concetti**. Si impareranno anche definizioni e concetti su come i computer elaborano il testo, inclusa l'analisi, la grammatica e l'identificazione di nomi e verbi. Ci sono alcune attività di codifica in questa lezione e vengono introdotti diversi concetti importanti che si imparerà a codificare più avanti nelle lezioni successive.
|
||||||
|
|
||||||
|
## Linguistica computazionale
|
||||||
|
|
||||||
|
La linguistica computazionale è un'area di ricerca e sviluppo che da molti decenni studia come i computer possono lavorare e persino capire, tradurre e comunicare con le lingue. L'elaborazione del linguaggio naturale (NLP) è un campo correlato incentrato su come i computer possono elaborare le lingue "naturali" o umane.
|
||||||
|
|
||||||
|
### Esempio: dettatura telefonica
|
||||||
|
|
||||||
|
Se si è mai dettato al telefono invece di digitare o posto una domanda a un assistente virtuale, il proprio discorso è stato convertito in formato testuale e quindi elaborato o *analizzato* dalla lingua con la quale si è parlato. Le parole chiave rilevate sono state quindi elaborate in un formato che il telefono o l'assistente possono comprendere e utilizzare.
|
||||||
|
|
||||||
|
![comprensione](../images/comprehension.png)
|
||||||
|
> La vera comprensione linguistica è difficile! Immagine di [Jen Looper](https://twitter.com/jenlooper)
|
||||||
|
|
||||||
|
### Come è resa possibile questa tecnologia?
|
||||||
|
|
||||||
|
Questo è possibile perché qualcuno ha scritto un programma per computer per farlo. Alcuni decenni fa, alcuni scrittori di fantascienza prevedevano che le persone avrebbero parlato principalmente con i loro computer e che i computer avrebbero sempre capito esattamente cosa intendevano. Purtroppo, si è rivelato essere un problema più difficile di quanto molti immaginavano, e sebbene sia un problema molto meglio compreso oggi, ci sono sfide significative nel raggiungere un'elaborazione del linguaggio naturale "perfetta" quando si tratta di comprendere il significato di una frase. Questo è un problema particolarmente difficile quando si tratta di comprendere l'umore o rilevare emozioni come il sarcasmo in una frase.
|
||||||
|
|
||||||
|
A questo punto, si potrebbero ricordare le lezioni scolastiche in cui l'insegnante ha coperto le parti della grammatica in una frase. In alcuni paesi, agli studenti viene insegnata la grammatica e la linguistica come materie dedicate, ma in molti questi argomenti sono inclusi nell'apprendimento di una lingua: o la prima lingua nella scuola primaria (imparare a leggere e scrivere) e forse una seconda lingua in post-primario o liceo. Non occorre preoccuparsi se non si è esperti nel distinguere i nomi dai verbi o gli avverbi dagli aggettivi!
|
||||||
|
|
||||||
|
Se si fa fatica a comprendere la differenza tra il *presente semplice* e il *presente progressivo*, non si è soli. Questa è una cosa impegnativa per molte persone, anche madrelingua di una lingua. La buona notizia è che i computer sono davvero bravi ad applicare regole formali e si imparerà a scrivere codice in grado di *analizzare* una frase così come un essere umano. La sfida più grande che si esaminerà in seguito è capire il *significato* e il *sentimento* di una frase.
|
||||||
|
|
||||||
|
## Prerequisiti
|
||||||
|
|
||||||
|
Per questa lezione, il prerequisito principale è essere in grado di leggere e comprendere la lingua di questa lezione. Non ci sono problemi di matematica o equazioni da risolvere. Sebbene l'autore originale abbia scritto questa lezione in inglese, è anche tradotta in altre lingue, quindi si potrebbe leggere una traduzione. Ci sono esempi in cui vengono utilizzati un numero di lingue diverse (per confrontare le diverse regole grammaticali di lingue diverse). Questi *non* sono tradotti, ma il testo esplicativo lo è, quindi il significato dovrebbe essere chiaro.
|
||||||
|
|
||||||
|
Per le attività di codifica, si utilizzerà Python e gli esempi utilizzano Python 3.8.
|
||||||
|
|
||||||
|
In questa sezione servirà e si utilizzerà:
|
||||||
|
|
||||||
|
- **Comprensione del linguaggio Python 3**. Questa lezione utilizza input, loop, lettura di file, array.
|
||||||
|
- **Visual Studio Code + estensione**. Si userà Visual Studio Code e la sua estensione Python. Si può anche usare un IDE Python a propria scelta.
|
||||||
|
- **TextBlob**. [TextBlob](https://github.com/sloria/TextBlob) è una libreria di elaborazione del testo semplificata per Python. Seguire le istruzioni sul sito TextBlob per installarlo sul proprio sistema (installare anche i corpora, come mostrato di seguito):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -U textblob
|
||||||
|
python -m textblob.download_corpora
|
||||||
|
```
|
||||||
|
|
||||||
|
> 💡 Suggerimento: si può eseguire Python direttamente negli ambienti VS Code. Controllare la [documentazione](https://code.visualstudio.com/docs/languages/python?WT.mc_id=academic-15963-cxa) per ulteriori informazioni.
|
||||||
|
|
||||||
|
## Parlare con le macchine
|
||||||
|
|
||||||
|
La storia del tentativo di far capire ai computer il linguaggio umano risale a decenni fa e uno dei primi scienziati a considerare l'elaborazione del linguaggio naturale è stato *Alan Turing*.
|
||||||
|
|
||||||
|
### Il Test di Turing.
|
||||||
|
|
||||||
|
Quando Turing stava facendo ricerche sull'*intelligenza artificiale* negli anni '50, considerò se un test di conversazione potesse essere somministrato a un essere umano e a un computer (tramite corrispondenza digitata) in cui l'essere umano nella conversazione non era sicuro se stesse conversando con un altro umano o un computer.
|
||||||
|
|
||||||
|
Se, dopo una certa durata di conversazione, l'essere umano non è riuscito a determinare se le risposte provenivano da un computer o meno, allora si potrebbe dire che il computer *sta pensando*?
|
||||||
|
|
||||||
|
### L'ispirazione - 'il gioco dell'imitazione'
|
||||||
|
|
||||||
|
L'idea è nata da un gioco di società chiamato *The Imitation Game* in cui un interrogatore è da solo in una stanza e ha il compito di determinare quale delle due persone (in un'altra stanza) sono rispettivamente maschio e femmina. L'interrogatore può inviare note e deve cercare di pensare a domande in cui le risposte scritte rivelano il sesso della persona misteriosa. Ovviamente, i giocatori nell'altra stanza stanno cercando di ingannare l'interrogatore rispondendo alle domande in modo tale da fuorviare o confondere l'interrogatore, dando anche l'impressione di rispondere onestamente.
|
||||||
|
|
||||||
|
### Lo sviluppo di Eliza
|
||||||
|
|
||||||
|
Negli anni '60 uno scienziato del MIT chiamato *Joseph* Weizenbaum sviluppò [*Eliza*](https:/wikipedia.org/wiki/ELIZA), un "terapista" informatico che poneva domande a un umano e dava l'impressione di comprendere le loro risposte. Tuttavia, mentre Eliza poteva analizzare una frase e identificare alcuni costrutti grammaticali e parole chiave in modo da dare una risposta ragionevole, non si poteva dire *che capisse* la frase. Se a Eliza viene presentata una frase che segue il formato "**Sono** _triste_", potrebbe riorganizzare e sostituire le parole nella frase per formare la risposta "Da quanto tempo **sei** _triste_".
|
||||||
|
|
||||||
|
Questo dava l'impressione che Eliza avesse capito la frase e stesse facendo una domanda successiva, mentre in realtà stava cambiando il tempo e aggiungendo alcune parole. Se Eliza non fosse stata in grado di identificare una parola chiave per la quale aveva una risposta, avrebbe dato invece una risposta casuale che potrebbe essere applicabile a molte frasi diverse. Eliza avrebbe potuto essere facilmente ingannata, ad esempio se un utente avesse scritto "**Sei** una _bicicletta_" avrebbe potuto rispondere con "Da quanto tempo **sono** una _bicicletta_?", invece di una risposta più ragionata.
|
||||||
|
|
||||||
|
[![Chiacchierare conEliza](https://img.youtube.com/vi/RMK9AphfLco/0.jpg)](https://youtu.be/RMK9AphfLco " Chiaccherare con Eliza")
|
||||||
|
|
||||||
|
> 🎥 Fare clic sull'immagine sopra per un video sul programma ELIZA originale
|
||||||
|
|
||||||
|
> Nota: si può leggere la descrizione originale di [Eliza](https://cacm.acm.org/magazines/1966/1/13317-elizaa-computer-program-for-the-study-of-natural-language-communication-between-man-and-machine/abstract) pubblicata nel 1966 se si dispone di un account ACM. In alternativa, leggere di Eliza su [wikipedia](https://it.wikipedia.org/wiki/ELIZA_(chatterbot))
|
||||||
|
|
||||||
|
## Esercizio: codificare un bot conversazionale di base
|
||||||
|
|
||||||
|
Un bot conversazionale, come Eliza, è un programma che sollecita l'input dell'utente e sembra capire e rispondere in modo intelligente. A differenza di Eliza, questo bot non avrà diverse regole che gli danno l'impressione di avere una conversazione intelligente. Invece, il bot avrà una sola capacità, per mantenere viva la conversazione con risposte casuali che potrebbero funzionare in quasi tutte le conversazioni banali.
|
||||||
|
|
||||||
|
### Il piano
|
||||||
|
|
||||||
|
I passaggi durante la creazione di un bot conversazionale:
|
||||||
|
|
||||||
|
1. Stampare le istruzioni che consigliano all'utente come interagire con il bot
|
||||||
|
2. Iniziare un ciclo
|
||||||
|
1. Accettare l'input dell'utente
|
||||||
|
2. Se l'utente ha chiesto di uscire, allora si esce
|
||||||
|
3. Elaborare l'input dell'utente e determinare la risposta (in questo caso, la risposta è una scelta casuale da un elenco di possibili risposte generiche)
|
||||||
|
4. Stampare la risposta
|
||||||
|
3. Riprendere il ciclo dal passaggio 2
|
||||||
|
|
||||||
|
### Costruire il bot
|
||||||
|
|
||||||
|
Si crea il bot. Si inizia definendo alcune frasi.
|
||||||
|
|
||||||
|
1. Creare questo bot in Python con le seguenti risposte casuali:
|
||||||
|
|
||||||
|
```python
|
||||||
|
random_responses = ["That is quite interesting, please tell me more.",
|
||||||
|
"I see. Do go on.",
|
||||||
|
"Why do you say that?",
|
||||||
|
"Funny weather we've been having, isn't it?",
|
||||||
|
"Let's change the subject.",
|
||||||
|
"Did you catch the game last night?"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Ecco un esempio di output come guida (l'input dell'utente è sulle righe che iniziano con `>`):
|
||||||
|
|
||||||
|
```output
|
||||||
|
Hello, I am Marvin, the simple robot.
|
||||||
|
You can end this conversation at any time by typing 'bye'
|
||||||
|
After typing each answer, press 'enter'
|
||||||
|
How are you today?
|
||||||
|
> I am good thanks
|
||||||
|
That is quite interesting, please tell me more.
|
||||||
|
> today I went for a walk
|
||||||
|
Did you catch the game last night?
|
||||||
|
> I did, but my team lost
|
||||||
|
Funny weather we've been having, isn't it?
|
||||||
|
> yes but I hope next week is better
|
||||||
|
Let's change the subject.
|
||||||
|
> ok, lets talk about music
|
||||||
|
Why do you say that?
|
||||||
|
> because I like music!
|
||||||
|
Why do you say that?
|
||||||
|
> bye
|
||||||
|
It was nice talking to you, goodbye!
|
||||||
|
```
|
||||||
|
|
||||||
|
Una possibile soluzione al compito è [qui](../solution/bot.py)
|
||||||
|
|
||||||
|
✅ Fermarsi e riflettere
|
||||||
|
|
||||||
|
1. Si ritiene che le risposte casuali "ingannerebbero" qualcuno facendogli pensare che il bot le abbia effettivamente capite?
|
||||||
|
2. Di quali caratteristiche avrebbe bisogno il bot per essere più efficace?
|
||||||
|
3. Se un bot potesse davvero "capire" il significato di una frase, avrebbe bisogno di "ricordare" anche il significato delle frasi precedenti in una conversazione?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Sfida
|
||||||
|
|
||||||
|
Scegliere uno degli elementi "fermarsi e riflettere" qui sopra e provare a implementarli nel codice o scrivere una soluzione su carta usando pseudocodice.
|
||||||
|
|
||||||
|
Nella prossima lezione si impareranno una serie di altri approcci all'analisi del linguaggio naturale e dell'machine learning.
|
||||||
|
|
||||||
|
## [Quiz post-lezione](https://jolly-sea-0a877260f.azurestaticapps.net/quiz/32/)
|
||||||
|
|
||||||
|
## Revisione e Auto Apprendimento
|
||||||
|
|
||||||
|
Dare un'occhiata ai riferimenti di seguito come ulteriori opportunità di lettura.
|
||||||
|
|
||||||
|
### Bibliografia
|
||||||
|
|
||||||
|
1. Schubert, Lenhart, "Computational Linguistics", *The Stanford Encyclopedia of Philosophy* (Edizione primavera 2020), Edward N. Zalta (a cura di), URL = <https://plato.stanford.edu/archives/spr2020/entries/computational-linguistics/>.
|
||||||
|
2. Università di Princeton "About WordNet". [WordNet](https://wordnet.princeton.edu/). Princeton University 2010.
|
||||||
|
|
||||||
|
## Compito
|
||||||
|
|
||||||
|
[Cercare un bot](assignment.it.md)
|
@ -0,0 +1,11 @@
|
|||||||
|
# Cercare un bot
|
||||||
|
|
||||||
|
## Istruzioni
|
||||||
|
|
||||||
|
I bot sono ovunque. Il compito: trovarne uno e adottarlo! È possibile trovarli sui siti web, nelle applicazioni bancarie e al telefono, ad esempio quando si chiamano società di servizi finanziari per consigli o informazioni sull'account. Analizzare il bot e vedire se si riesce a confonderlo. Se si riesce a confondere il bot, perché si pensa sia successo? Scrivere un breve articolo sulla propria esperienza.
|
||||||
|
|
||||||
|
## Rubrica
|
||||||
|
|
||||||
|
| Criteri | Ottimo | Adeguato | Necessita miglioramento |
|
||||||
|
| -------- | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | --------------------- |
|
||||||
|
| | Viene scritto un documento a pagina intera, che spiega la presunta architettura del bot e delinea l'esperienza con esso | Un documento è incompleto o non ben concepito | Nessun documento inviato |
|
@ -0,0 +1,214 @@
|
|||||||
|
# Compiti e tecniche comuni di elaborazione del linguaggio naturale
|
||||||
|
|
||||||
|
Per la maggior parte delle attività di *elaborazione del linguaggio naturale* , il testo da elaborare deve essere suddiviso, esaminato e i risultati archiviati o incrociati con regole e insiemi di dati. Queste attività consentono al programmatore di derivare il _significato_ o l'_intento_ o solo la _frequenza_ di termini e parole in un testo.
|
||||||
|
|
||||||
|
## [Quiz Pre-Lezione](https://jolly-sea-0a877260f.azurestaticapps.net/quiz/33/)
|
||||||
|
|
||||||
|
Si esaminano le comuni tecniche utilizzate nell'elaborazione del testo. Combinate con machine learning, queste tecniche aiutano ad analizzare grandi quantità di testo in modo efficiente. Prima di applicare machine learning a queste attività, tuttavia, occorre cercare di comprendere i problemi incontrati da uno specialista in NLP.
|
||||||
|
|
||||||
|
## Compiti comuni per NLP
|
||||||
|
|
||||||
|
Esistono diversi modi per analizzare un testo su cui si sta lavorando. Ci sono attività che si possono eseguire e attraverso le quali si è in grado di valutare la comprensione del testo e trarre conclusioni. Di solito si eseguono queste attività in sequenza.
|
||||||
|
|
||||||
|
### Tokenizzazione
|
||||||
|
|
||||||
|
Probabilmente la prima cosa che la maggior parte degli algoritmi di NLP deve fare è dividere il testo in token o parole. Anche se questo sembra semplice, dover tenere conto della punteggiatura e dei delimitatori di parole e frasi di lingue diverse può renderlo complicato. Potrebbe essere necessario utilizzare vari metodi per determinare le demarcazioni.
|
||||||
|
|
||||||
|
![Tokenizzazione](../images/tokenization.png)
|
||||||
|
> Tokenizzazione di una frase da **Orgoglio e Pregiudizio**. Infografica di [Jen Looper](https://twitter.com/jenlooper)
|
||||||
|
|
||||||
|
### Embedding
|
||||||
|
|
||||||
|
I [word embeddings](https://it.wikipedia.org/wiki/Word_embedding) sono un modo per convertire numericamente i dati di testo. Gli embedding vengono eseguiti in modo tale che le parole con un significato simile o le parole usate insieme vengano raggruppate insieme.
|
||||||
|
|
||||||
|
![word embeddings](../images/embedding.png)
|
||||||
|
> "I have the highest respect for your nerves, they are my old friends." - Incorporazioni di parole per una frase in **Orgoglio e Pregiudizio**. Infografica di [Jen Looper](https://twitter.com/jenlooper)
|
||||||
|
|
||||||
|
✅ Provare [questo interessante strumento](https://projector.tensorflow.org/) per sperimentare i word embedding. Facendo clic su una parola vengono visualizzati gruppi di parole simili: gruppi di "toy" con "disney", "lego", "playstation" e "console".
|
||||||
|
|
||||||
|
### Analisi e codifica di parti del discorso
|
||||||
|
|
||||||
|
Ogni parola che è stata tokenizzata può essere etichettata come parte del discorso: un sostantivo, un verbo o un aggettivo. La frase `the quick red fox jumped over the lazy brown dog` potrebbe essere etichettata come fox = sostantivo, jumped = verbo.
|
||||||
|
|
||||||
|
![elaborazione](../images/parse.png)
|
||||||
|
|
||||||
|
> Analisi di una frase da **Orgoglio e Pregiudizio**. Infografica di [Jen Looper](https://twitter.com/jenlooper)
|
||||||
|
|
||||||
|
L'analisi consiste nel riconoscere quali parole sono correlate tra loro in una frase - per esempio `the quick red fox jumped` è una sequenza aggettivo-sostantivo-verbo che è separata dalla sequenza `lazy brown dog` .
|
||||||
|
|
||||||
|
### Frequenze di parole e frasi
|
||||||
|
|
||||||
|
Una procedura utile quando si analizza un corpo di testo di grandi dimensioni è creare un dizionario di ogni parola o frase di interesse e con quale frequenza viene visualizzata. La frase `the quick red fox jumped over the lazy brown dog` ha una frequenza di parole di 2 per the.
|
||||||
|
|
||||||
|
Si esamina un testo di esempio in cui si conta la frequenza delle parole. La poesia di Rudyard Kipling The Winners contiene i seguenti versi:
|
||||||
|
|
||||||
|
```output
|
||||||
|
What the moral? Who rides may read.
|
||||||
|
When the night is thick and the tracks are blind
|
||||||
|
A friend at a pinch is a friend, indeed,
|
||||||
|
But a fool to wait for the laggard behind.
|
||||||
|
Down to Gehenna or up to the Throne,
|
||||||
|
He travels the fastest who travels alone.
|
||||||
|
```
|
||||||
|
|
||||||
|
Poiché le frequenze delle frasi possono essere o meno insensibili alle maiuscole o alle maiuscole, a seconda di quanto richiesto, la frase `a friend` ha una frequenza di 2, `the` ha una frequenza di 6 e `travels` è 2.
|
||||||
|
|
||||||
|
### N-grammi
|
||||||
|
|
||||||
|
Un testo può essere suddiviso in sequenze di parole di una lunghezza prestabilita, una parola singola (unigramma), due parole (bigrammi), tre parole (trigrammi) o un numero qualsiasi di parole (n-grammi).
|
||||||
|
|
||||||
|
Ad esempio, `the quick red fox jumped over the lazy brown dog` con un punteggio n-grammo di 2 produce i seguenti n-grammi:
|
||||||
|
|
||||||
|
1. the quick
|
||||||
|
2. quick red
|
||||||
|
3. red fox
|
||||||
|
4. fox jumped
|
||||||
|
5. jumped over
|
||||||
|
6. over the
|
||||||
|
7. the lazy
|
||||||
|
8. lazy brown
|
||||||
|
9. brown dog
|
||||||
|
|
||||||
|
Potrebbe essere più facile visualizzarlo come una casella scorrevole per la frase. Qui è per n-grammi di 3 parole, l'n-grammo è in grassetto in ogni frase:
|
||||||
|
|
||||||
|
1. **the quick red** fox jumped over the lazy brown dog
|
||||||
|
2. the **quick red fox** jumped over the lazy brown dog
|
||||||
|
3. the quick **red fox jumped** over the lazy brown dog
|
||||||
|
4. the quick red **fox jumped over** the lazy brown dog
|
||||||
|
5. the quick red fox **jumped over the** lazy brown dog
|
||||||
|
6. the quick red fox jumped **over the lazy** brown dog
|
||||||
|
7. the quick red fox jumped over **the lazy brown** dog
|
||||||
|
8. the quick red fox jumped over the **lazy brown dog**
|
||||||
|
|
||||||
|
![finestra scorrevole n-grammi](../images/n-grams.gif)
|
||||||
|
|
||||||
|
> Valore N-gram di 3: Infografica di [Jen Looper](https://twitter.com/jenlooper)
|
||||||
|
|
||||||
|
### Estrazione frase nominale
|
||||||
|
|
||||||
|
Nella maggior parte delle frasi, c'è un sostantivo che è il soggetto o l'oggetto della frase. In inglese, è spesso identificabile con "a" o "an" o "the" che lo precede. Identificare il soggetto o l'oggetto di una frase "estraendo la frase nominale" è un compito comune in NLP quando si cerca di capire il significato di una frase.
|
||||||
|
|
||||||
|
✅ Nella frase "I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation. It is too long ago. I was in the middle before I knew that I had begun.", si possono identificare i nomi nelle frasi?
|
||||||
|
|
||||||
|
Nella frase `the quick red fox jumped over the lazy brown dog` ci sono 2 frasi nominali: **quick red fox** e **lazy brown dog**.
|
||||||
|
|
||||||
|
### Analisi del sentiment
|
||||||
|
|
||||||
|
Una frase o un testo può essere analizzato per il sentimento, o quanto *positivo* o *negativo* esso sia. Il sentimento si misura in *polarità* e *oggettività/soggettività*. La polarità è misurata da -1,0 a 1,0 (da negativo a positivo) e da 0,0 a 1,0 (dal più oggettivo al più soggettivo).
|
||||||
|
|
||||||
|
✅ In seguito si imparerà che ci sono diversi modi per determinare il sentimento usando machine learning ma un modo è avere un elenco di parole e frasi che sono classificate come positive o negative da un esperto umano e applicare quel modello al testo per calcolare un punteggio di polarità. Si riesce a vedere come funzionerebbe in alcune circostanze e meno bene in altre?
|
||||||
|
|
||||||
|
### Inflessione
|
||||||
|
|
||||||
|
L'inflessione consente di prendere una parola e ottenere il singolare o il plurale della parola.
|
||||||
|
|
||||||
|
### Lemmatizzazione
|
||||||
|
|
||||||
|
Un *lemma* è la radice o il lemma per un insieme di parole, ad esempio *volò*, *vola*, *volando* ha un lemma del verbo *volare*.
|
||||||
|
|
||||||
|
Ci sono anche utili database disponibili per il ricercatore NPL, in particolare:
|
||||||
|
|
||||||
|
### WordNet
|
||||||
|
|
||||||
|
[WordNet](https://wordnet.princeton.edu/) è un database di parole, sinonimi, contari e molti altri dettagli per ogni parola in molte lingue diverse. È incredibilmente utile quando si tenta di costruire traduzioni, correttori ortografici o strumenti di lingua di qualsiasi tipo.
|
||||||
|
|
||||||
|
## Librerie NPL
|
||||||
|
|
||||||
|
Fortunatamente, non è necessario creare tutte queste tecniche da soli, poiché sono disponibili eccellenti librerie Python che le rendono molto più accessibili agli sviluppatori che non sono specializzati nell'elaborazione del linguaggio naturale o in machine learning. Le prossime lezioni includono altri esempi di queste, ma qui si impareranno alcuni esempi utili che aiuteranno con il prossimo compito.
|
||||||
|
|
||||||
|
### Esercizio: utilizzo della libreria `TextBlob`
|
||||||
|
|
||||||
|
Si usa una libreria chiamata TextBlob in quanto contiene API utili per affrontare questi tipi di attività. TextBlob "sta sulle spalle giganti di [NLTK](https://nltk.org) e [pattern](https://github.com/clips/pattern), e si sposa bene con entrambi". Ha una notevole quantità di ML incorporato nella sua API.
|
||||||
|
|
||||||
|
> Nota: per TextBlob è disponibile un'utile [guida rapida](https://textblob.readthedocs.io/en/dev/quickstart.html#quickstart), consigliata per sviluppatori Python esperti
|
||||||
|
|
||||||
|
Quando si tenta di identificare *le frasi nominali*, TextBlob offre diverse opzioni di estrattori per trovarle.
|
||||||
|
|
||||||
|
1. Dare un'occhiata a `ConllExtractor`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from textblob import TextBlob
|
||||||
|
from textblob.np_extractors import ConllExtractor
|
||||||
|
# importa e crea un extrattore Conll da usare successivamente
|
||||||
|
extractor = ConllExtractor()
|
||||||
|
|
||||||
|
# quando serve un estrattore di frasi nominali:
|
||||||
|
user_input = input("> ")
|
||||||
|
user_input_blob = TextBlob(user_input, np_extractor=extractor) # notare specificato estrattore non predefinito
|
||||||
|
np = user_input_blob.noun_phrases
|
||||||
|
```
|
||||||
|
|
||||||
|
> Cosa sta succedendo qui? [ConllExtractor](https://textblob.readthedocs.io/en/dev/api_reference.html?highlight=Conll#textblob.en.np_extractors.ConllExtractor) è "Un estrattore di frasi nominali che utilizza l'analisi dei blocchi addestrata con il corpus di formazione ConLL-2000". ConLL-2000 si riferisce alla Conferenza del 2000 sull'apprendimento computazionale del linguaggio naturale. Ogni anno la conferenza ha ospitato un workshop per affrontare uno spinoso problema della NPL, e nel 2000 è stato lo spezzettamento dei sostantivi. Un modello è stato addestrato sul Wall Street Journal, con "sezioni 15-18 come dati di addestramento (211727 token) e sezione 20 come dati di test (47377 token)". Si possono guardare le procedure utilizzate [qui](https://www.clips.uantwerpen.be/conll2000/chunking/) e i [risultati](https://ifarm.nl/erikt/research/np-chunking.html).
|
||||||
|
|
||||||
|
### Sfida: migliorare il bot con NPL
|
||||||
|
|
||||||
|
Nella lezione precedente si è creato un bot di domande e risposte molto semplice. Ora si renderà Marvin un po' più comprensivo analizzando l'input per il sentimento e stampando una risposta che corrisponda al sentimento. Si dovrà anche identificare una frase nominale `noun_phrase` e chiedere informazioni su di essa.
|
||||||
|
|
||||||
|
I passaggi durante la creazione di un bot conversazionale:
|
||||||
|
|
||||||
|
1. Stampare le istruzioni che consigliano all'utente come interagire con il bot
|
||||||
|
2. Avviare il ciclo
|
||||||
|
1. Accettare l'input dell'utente
|
||||||
|
2. Se l'utente ha chiesto di uscire, allora si esce
|
||||||
|
3. Elaborare l'input dell'utente e determinare la risposta di sentimento appropriata
|
||||||
|
4. Se viene rilevata una frase nominale nel sentimento, pluralizzala e chiedere ulteriori input su quell'argomento
|
||||||
|
5. Stampare la risposta
|
||||||
|
3. Riprendere il ciclo dal passo 2
|
||||||
|
|
||||||
|
Ecco il frammento di codice per determinare il sentimento usando TextBlob. Si noti che ci sono solo quattro *gradienti* di risposta al sentimento (se ne potrebbero avere di più se lo si desidera):
|
||||||
|
|
||||||
|
```python
|
||||||
|
if user_input_blob.polarity <= -0.5:
|
||||||
|
response = "Oh dear, that sounds bad. " # Oh caro, è terribile
|
||||||
|
elif user_input_blob.polarity <= 0:
|
||||||
|
response = "Hmm, that's not great. " # Mmm, non è eccezionale
|
||||||
|
elif user_input_blob.polarity <= 0.5:
|
||||||
|
response = "Well, that sounds positive. " # Bene, questo è positivo
|
||||||
|
elif user_input_blob.polarity <= 1:
|
||||||
|
response = "Wow, that sounds great. " # Wow, sembra eccezionale
|
||||||
|
```
|
||||||
|
|
||||||
|
Ecco un risultato di esempio a scopo di guida (l'input utente è sulle righe che iniziano per >):
|
||||||
|
|
||||||
|
```output
|
||||||
|
Hello, I am Marvin, the friendly robot.
|
||||||
|
You can end this conversation at any time by typing 'bye'
|
||||||
|
After typing each answer, press 'enter'
|
||||||
|
How are you today?
|
||||||
|
> I am ok
|
||||||
|
Well, that sounds positive. Can you tell me more?
|
||||||
|
> I went for a walk and saw a lovely cat
|
||||||
|
Well, that sounds positive. Can you tell me more about lovely cats?
|
||||||
|
> cats are the best. But I also have a cool dog
|
||||||
|
Wow, that sounds great. Can you tell me more about cool dogs?
|
||||||
|
> I have an old hounddog but he is sick
|
||||||
|
Hmm, that's not great. Can you tell me more about old hounddogs?
|
||||||
|
> bye
|
||||||
|
It was nice talking to you, goodbye!
|
||||||
|
```
|
||||||
|
|
||||||
|
Una possibile soluzione al compito è [qui](../solution/bot.py)
|
||||||
|
|
||||||
|
Verifica delle conoscenze
|
||||||
|
|
||||||
|
1. Si ritiene che le risposte casuali "ingannerebbero" qualcuno facendogli pensare che il bot le abbia effettivamente capite?
|
||||||
|
2. Identificare la frase nominale rende il bot più 'credibile'?
|
||||||
|
3. Perché estrarre una "frase nominale" da una frase sarebbe una cosa utile da fare?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Implementare il bot nel controllo delle conoscenze precedenti e testarlo su un amico. Può ingannarlo? Si può rendere il bot più 'credibile?'
|
||||||
|
|
||||||
|
## 🚀 Sfida
|
||||||
|
|
||||||
|
Prendere un'attività dalla verifica delle conoscenze qui sopra e provare a implementarla. Provare il bot su un amico. Può ingannarlo? Si può rendere il bot più 'credibile?'
|
||||||
|
|
||||||
|
## [Quiz post-lezione](https://jolly-sea-0a877260f.azurestaticapps.net/quiz/34/)
|
||||||
|
|
||||||
|
## Revisione e Auto Apprendimento
|
||||||
|
|
||||||
|
Nelle prossime lezioni si imparerà di più sull'analisi del sentiment. Fare ricerche su questa interessante tecnica in articoli come questi su [KDNuggets](https://www.kdnuggets.com/tag/nlp)
|
||||||
|
|
||||||
|
## Compito
|
||||||
|
|
||||||
|
[Fare rispondere un bot](assignment.it.md)
|
@ -0,0 +1,11 @@
|
|||||||
|
# Fare rispondere un bot
|
||||||
|
|
||||||
|
## Istruzioni
|
||||||
|
|
||||||
|
Nelle ultime lezioni, si è programmato un bot di base con cui chattare. Questo bot fornisce risposte casuali finché non si dice ciao ("bye"). Si possono rendere le risposte un po' meno casuali e attivare le risposte se si dicono cose specifiche, come "perché" o "come"? Si pensi a come machine learning potrebbe rendere questo tipo di lavoro meno manuale mentre si estende il bot. Si possono utilizzare le librerie NLTK o TextBlob per semplificare le attività.
|
||||||
|
|
||||||
|
## Rubrica
|
||||||
|
|
||||||
|
| Criteri | Ottimo | Adeguato | Necessita miglioramento |
|
||||||
|
| -------- | --------------------------------------------- | ------------------------------------------------ | ----------------------- |
|
||||||
|
| | Viene presentato e documentato un nuovo file bot.py | Viene presentato un nuovo file bot ma contiene bug | Non viene presentato un file |
|
@ -0,0 +1,5 @@
|
|||||||
|
# NLTK
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
NLTK is a well-known library for use in computational linguistics and NLP. Take this opportunity to read through the '[NLTK book](https://www.nltk.org/book/)' and try out its exercises. In this ungraded assignment, you will get to know this library more deeply.
|
@ -0,0 +1,376 @@
|
|||||||
|
# Analisi del sentiment con recensioni di hotel
|
||||||
|
|
||||||
|
Ora che si è esplorato in dettaglio l'insieme di dati, è il momento di filtrare le colonne e quindi utilizzare le tecniche NLP sull'insieme di dati per ottenere nuove informazioni sugli hotel.
|
||||||
|
|
||||||
|
## [Quiz Pre-Lezione](https://jolly-sea-0a877260f.azurestaticapps.net/quiz/39/)
|
||||||
|
|
||||||
|
### Operazioni di Filtraggio e Analisi del Sentiment
|
||||||
|
|
||||||
|
Come probabilmente notato, l'insieme di dati presenta alcuni problemi. Alcune colonne sono piene di informazioni inutili, altre sembrano errate. Se sono corrette, non è chiaro come sono state calcolate e le risposte non possono essere verificate in modo indipendente dai propri calcoli.
|
||||||
|
|
||||||
|
## Esercizio: un po' più di elaborazione dei dati
|
||||||
|
|
||||||
|
Occorre pulire un po' di più i dati. Si aggiungono colonne che saranno utili in seguito, si modificano i valori in altre colonne e si eliminano completamente determinate colonne.
|
||||||
|
|
||||||
|
1. Elaborazione iniziale colonne
|
||||||
|
|
||||||
|
1. Scartare `lat` e `lng`
|
||||||
|
|
||||||
|
2. Sostituire i valori `Hotel_Address` con i seguenti valori (se l'indirizzo contiene lo stesso della città e del paese, si cambia solo con la città e la nazione).
|
||||||
|
|
||||||
|
Queste sono le uniche città e nazioni nell'insieme di dati:
|
||||||
|
|
||||||
|
Amsterdam, Netherlands
|
||||||
|
|
||||||
|
Barcelona, Spain
|
||||||
|
|
||||||
|
London, United Kingdom
|
||||||
|
|
||||||
|
Milan, Italy
|
||||||
|
|
||||||
|
Paris, France
|
||||||
|
|
||||||
|
Vienna, Austria
|
||||||
|
|
||||||
|
```python
|
||||||
|
def replace_address(row):
|
||||||
|
if "Netherlands" in row["Hotel_Address"]:
|
||||||
|
return "Amsterdam, Netherlands"
|
||||||
|
elif "Barcelona" in row["Hotel_Address"]:
|
||||||
|
return "Barcelona, Spain"
|
||||||
|
elif "United Kingdom" in row["Hotel_Address"]:
|
||||||
|
return "London, United Kingdom"
|
||||||
|
elif "Milan" in row["Hotel_Address"]:
|
||||||
|
return "Milan, Italy"
|
||||||
|
elif "France" in row["Hotel_Address"]:
|
||||||
|
return "Paris, France"
|
||||||
|
elif "Vienna" in row["Hotel_Address"]:
|
||||||
|
return "Vienna, Austria"
|
||||||
|
|
||||||
|
# Sostituisce tutti gli indirizzi con una forma ridotta più utile
|
||||||
|
df["Hotel_Address"] = df.apply(replace_address, axis = 1)
|
||||||
|
# La somma di value_counts() dovrebbe sommarsi al numero totale recensioni
|
||||||
|
print(df["Hotel_Address"].value_counts())
|
||||||
|
```
|
||||||
|
|
||||||
|
Ora si possono interrogare i dati a livello di nazione:
|
||||||
|
|
||||||
|
```python
|
||||||
|
display(df.groupby("Hotel_Address").agg({"Hotel_Name": "nunique"}))
|
||||||
|
```
|
||||||
|
|
||||||
|
| Hotel_Address | Hotel_Name (Nome Hotel) |
|
||||||
|
| :--------------------- | :--------: |
|
||||||
|
| Amsterdam, Paesi Bassi | 105 |
|
||||||
|
| Barcellona, Spagna | 211 |
|
||||||
|
| Londra, Regno Unito | 400 |
|
||||||
|
| Milano, Italia | 162 |
|
||||||
|
| Parigi, Francia | 458 |
|
||||||
|
| Vienna, Austria | 158 |
|
||||||
|
|
||||||
|
2. Elaborazione colonne di meta-recensione dell'hotel
|
||||||
|
|
||||||
|
1. Eliminare `Additional_Number_of_Scoring`
|
||||||
|
|
||||||
|
1. Sostituire `Total_Number_of_Reviews` con il numero totale di recensioni per quell'hotel che sono effettivamente nell'insieme di dati
|
||||||
|
|
||||||
|
1. Sostituire `Average_Score` con il punteggio calcolato via codice
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Elimina `Additional_Number_of_Scoring`
|
||||||
|
df.drop(["Additional_Number_of_Scoring"], axis = 1, inplace=True)
|
||||||
|
# Sostituisce `Total_Number_of_Reviews` e `Average_Score` con i propri valori calcolati
|
||||||
|
df.Total_Number_of_Reviews = df.groupby('Hotel_Name').transform('count')
|
||||||
|
df.Average_Score = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Elaborazione delle colonne di recensione
|
||||||
|
|
||||||
|
1. Eliminare `Review_Total_Negative_Word_Counts`, `Review_Total_Positive_Word_Counts`, `Review_Date` e `days_since_review`
|
||||||
|
|
||||||
|
2. Mantenere `Reviewer_Score`, `Negative_Review` e `Positive_Review` così come sono
|
||||||
|
|
||||||
|
3. Conservare i `Tags` per ora
|
||||||
|
|
||||||
|
- Si faranno alcune operazioni di filtraggio aggiuntive sui tag nella prossima sezione, successivamente i tag verranno eliminati
|
||||||
|
|
||||||
|
4. Elaborazione delle colonne del recensore
|
||||||
|
|
||||||
|
1. Scartare `Total_Number_of_Reviews_Reviewer_Has_Given`
|
||||||
|
|
||||||
|
2. Mantenere `Reviewer_Nationality`
|
||||||
|
|
||||||
|
### Colonne tag
|
||||||
|
|
||||||
|
Le colonne `Tag` sono problematiche in quanto si tratta di un elenco (in formato testo) memorizzato nella colonna. Purtroppo l'ordine e il numero delle sottosezioni in questa colonna non sono sempre gli stessi. È difficile per un essere umano identificare le frasi corrette a cui essere interessato, perché ci sono 515.000 righe e 1427 hotel e ognuno ha opzioni leggermente diverse che un recensore potrebbe scegliere. È qui che la NLP brilla. Si può scansionare il testo, trovare le frasi più comuni e contarle.
|
||||||
|
|
||||||
|
Purtroppo non interessano parole singole, ma frasi composte da più parole (es. *Viaggio di lavoro*). L'esecuzione di un algoritmo di distribuzione della frequenza a più parole su così tanti dati (6762646 parole) potrebbe richiedere una quantità straordinaria di tempo, ma senza guardare i dati, sembrerebbe che sia una spesa necessaria. È qui che l'analisi dei dati esplorativi diventa utile, perché si è visto un esempio di tag come `["Business trip", "Solo traveler", "Single Room", "Stayed 5 nights", "Submitted from a mobile device"]` , si può iniziare a chiedersi se è possibile ridurre notevolmente l'elaborazione da fare. Fortunatamente lo è, ma prima occorre seguire alcuni passaggi per accertare i tag di interesse.
|
||||||
|
|
||||||
|
### Filtraggio tag
|
||||||
|
|
||||||
|
Ricordare che l'obiettivo dell'insieme di dati è aggiungere il sentiment e le colonne che aiuteranno a scegliere l'hotel migliore (per se stessi o forse per un cliente che incarica di creare un bot di raccomandazione dell'hotel). Occorre chiedersi se i tag sono utili o meno nell'insieme di dati finale. Ecco un'interpretazione (se serve l'insieme di dati per altri motivi diversi tag potrebbero rimanere dentro/fuori dalla selezione):
|
||||||
|
|
||||||
|
1. Il tipo di viaggio è rilevante e dovrebbe rimanere
|
||||||
|
2. Il tipo di gruppo di ospiti è importante e dovrebbe rimanere
|
||||||
|
3. Il tipo di camera, suite o monolocale in cui ha soggiornato l'ospite è irrilevante (tutti gli hotel hanno praticamente le stesse stanze)
|
||||||
|
4. Il dispositivo su cui è stata inviata la recensione è irrilevante
|
||||||
|
5. Il numero di notti in cui il recensore ha soggiornato *potrebbe* essere rilevante se si attribuisce a soggiorni più lunghi un gradimento maggiore per l'hotel, ma è una forzatura e probabilmente irrilevante
|
||||||
|
|
||||||
|
In sintesi, si **mantengono 2 tipi di tag e si rimuove il resto**.
|
||||||
|
|
||||||
|
Innanzitutto, non si vogliono contare i tag finché non sono in un formato migliore, quindi ciò significa rimuovere le parentesi quadre e le virgolette. Si può fare in diversi modi, ma serve il più veloce in quanto potrebbe richiedere molto tempo per elaborare molti dati. Fortunatamente, pandas ha un modo semplice per eseguire ciascuno di questi passaggi.
|
||||||
|
|
||||||
|
```Python
|
||||||
|
# Rimuove le parentesi quadre di apertura e chiusura
|
||||||
|
df.Tags = df.Tags.str.strip("[']")
|
||||||
|
# rimuove anche tutte le virgolette
|
||||||
|
df.Tags = df.Tags.str.replace(" ', '", ",", regex = False)
|
||||||
|
```
|
||||||
|
|
||||||
|
Ogni tag diventa qualcosa come: `Business trip, Solo traveler, Single Room, Stayed 5 nights, Submitted from a mobile device`.
|
||||||
|
|
||||||
|
Successivamente si manifesta un problema. Alcune recensioni, o righe, hanno 5 colonne, altre 3, altre 6. Questo è il risultato di come è stato creato l'insieme di dati ed è difficile da risolvere. Si vuole ottenere un conteggio della frequenza di ogni frase, ma sono in ordine diverso in ogni recensione, quindi il conteggio potrebbe essere disattivato e un hotel potrebbe non ricevere un tag assegnato per ciò che meritava.
|
||||||
|
|
||||||
|
Si utilizzerà invece l'ordine diverso a proprio vantaggio, perché ogni tag è composto da più parole ma anche separato da una virgola! Il modo più semplice per farlo è creare 6 colonne temporanee con ogni tag inserito nella colonna corrispondente al suo ordine nel tag. Quindi si uniscono le 6 colonne in una grande colonna e si esegue il metodo `value_counts()` sulla colonna risultante. Stampandolo, si vedrà che c'erano 2428 tag univoci. Ecco un piccolo esempio:
|
||||||
|
|
||||||
|
| Tag | Count |
|
||||||
|
| ------------------------------ | ------ |
|
||||||
|
| Leisure trip | 417778 |
|
||||||
|
| Submitted from a mobile device | 307640 |
|
||||||
|
| Couple | 252294 |
|
||||||
|
| Stayed 1 night | 193645 |
|
||||||
|
| Stayed 2 nights | 133937 |
|
||||||
|
| Solo traveler | 108545 |
|
||||||
|
| Stayed 3 nights | 95821 |
|
||||||
|
| Business trip | 82939 |
|
||||||
|
| Group | 65392 |
|
||||||
|
| Family with young children | 61015 |
|
||||||
|
| Stayed 4 nights | 47817 |
|
||||||
|
| Double Room | 35207 |
|
||||||
|
| Standard Double Room | 32248 |
|
||||||
|
| Superior Double Room | 31393 |
|
||||||
|
| Family with older children | 26349 |
|
||||||
|
| Deluxe Double Room | 24823 |
|
||||||
|
| Double or Twin Room | 22393 |
|
||||||
|
| Stayed 5 nights | 20845 |
|
||||||
|
| Standard Double or Twin Room | 17483 |
|
||||||
|
| Classic Double Room | 16989 |
|
||||||
|
| Superior Double or Twin Room | 13570 |
|
||||||
|
| 2 rooms | 12393 |
|
||||||
|
|
||||||
|
Alcuni dei tag comuni come `Submitted from a mobile device` non sono di alcuna utilità, quindi potrebbe essere una cosa intelligente rimuoverli prima di contare l'occorrenza della frase, ma è un'operazione così veloce che si possono lasciare e ignorare.
|
||||||
|
|
||||||
|
### Rimozione della durata dai tag di soggiorno
|
||||||
|
|
||||||
|
La rimozione di questi tag è il passaggio 1, riduce leggermente il numero totale di tag da considerare. Notare che non si rimuovono dall'insieme di dati, si sceglie semplicemente di rimuoverli dalla considerazione come valori da contare/mantenere nell'insieme di dati delle recensioni.
|
||||||
|
|
||||||
|
| Length of stay | Count |
|
||||||
|
| ---------------- | ------ |
|
||||||
|
| Stayed 1 night | 193645 |
|
||||||
|
| Stayed 2 nights | 133937 |
|
||||||
|
| Stayed 3 nights | 95821 |
|
||||||
|
| Stayed 4 nights | 47817 |
|
||||||
|
| Stayed 5 nights | 20845 |
|
||||||
|
| Stayed 6 nights | 9776 |
|
||||||
|
| Stayed 7 nights | 7399 |
|
||||||
|
| Stayed 8 nights | 2502 |
|
||||||
|
| Stayed 9 nights | 1293 |
|
||||||
|
| ... | ... |
|
||||||
|
|
||||||
|
C'è una grande varietà di camere, suite, monolocali, appartamenti e così via. Significano tutti più o meno la stessa cosa e non sono rilevanti allo scopo, quindi si rimuovono dalla considerazione.
|
||||||
|
|
||||||
|
| Type of room | Count |
|
||||||
|
| ----------------------------- | ----- |
|
||||||
|
| Double Room | 35207 |
|
||||||
|
| Standard Double Room | 32248 |
|
||||||
|
| Superior Double Room | 31393 |
|
||||||
|
| Deluxe Double Room | 24823 |
|
||||||
|
| Double or Twin Room | 22393 |
|
||||||
|
| Standard Double or Twin Room | 17483 |
|
||||||
|
| Classic Double Room | 16989 |
|
||||||
|
| Superior Double or Twin Room | 13570 |
|
||||||
|
|
||||||
|
Infine, e questo è delizioso (perché non ha richiesto molta elaborazione), rimarranno i seguenti tag *utili*:
|
||||||
|
|
||||||
|
| Tag | Count |
|
||||||
|
| --------------------------------------------- | ------ |
|
||||||
|
| Leisure trip | 417778 |
|
||||||
|
| Couple | 252294 |
|
||||||
|
| Solo traveler | 108545 |
|
||||||
|
| Business trip | 82939 |
|
||||||
|
| Group (combined with Travellers with friends) | 67535 |
|
||||||
|
| Family with young children | 61015 |
|
||||||
|
| Family with older children | 26349 |
|
||||||
|
| With a pet | 1405 |
|
||||||
|
|
||||||
|
Si potrebbe obiettare che `Travellers with friends` (Viaggiatori con amici) è più o meno lo stesso di `Group` (Gruppo), e sarebbe giusto combinare i due come fatto sopra. Il codice per identificare i tag corretti è [il notebook Tags](../solution/1-notebook.ipynb).
|
||||||
|
|
||||||
|
Il passaggio finale consiste nel creare nuove colonne per ciascuno di questi tag. Quindi, per ogni riga di recensione, se la colonna `Tag` corrisponde a una delle nuove colonne, aggiungere 1, in caso contrario aggiungere 0. Il risultato finale sarà un conteggio di quanti recensori hanno scelto questo hotel (in aggregato) per, ad esempio, affari o piacere, o per portare un animale domestico, e questa è un'informazione utile quando consiglia un hotel.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Elabora Tags in nuove colonne
|
||||||
|
# Il file Hotel_Reviews_Tags.py, identifica i tag più importanti
|
||||||
|
# Leisure trip, Couple, Solo traveler, Business trip, Group combinato con Travelers with friends,
|
||||||
|
# Family with young children, Family with older children, With a pet
|
||||||
|
df["Leisure_trip"] = df.Tags.apply(lambda tag: 1 if "Leisure trip" in tag else 0)
|
||||||
|
df["Couple"] = df.Tags.apply(lambda tag: 1 if "Couple" in tag else 0)
|
||||||
|
df["Solo_traveler"] = df.Tags.apply(lambda tag: 1 if "Solo traveler" in tag else 0)
|
||||||
|
df["Business_trip"] = df.Tags.apply(lambda tag: 1 if "Business trip" in tag else 0)
|
||||||
|
df["Group"] = df.Tags.apply(lambda tag: 1 if "Group" in tag or "Travelers with friends" in tag else 0)
|
||||||
|
df["Family_with_young_children"] = df.Tags.apply(lambda tag: 1 if "Family with young children" in tag else 0)
|
||||||
|
df["Family_with_older_children"] = df.Tags.apply(lambda tag: 1 if "Family with older children" in tag else 0)
|
||||||
|
df["With_a_pet"] = df.Tags.apply(lambda tag: 1 if "With a pet" in tag else 0)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Salvare il file.
|
||||||
|
|
||||||
|
Infine, salvare l'insieme di dati così com'è ora con un nuovo nome.
|
||||||
|
|
||||||
|
```python
|
||||||
|
df.drop(["Review_Total_Negative_Word_Counts", "Review_Total_Positive_Word_Counts", "days_since_review", "Total_Number_of_Reviews_Reviewer_Has_Given"], axis = 1, inplace=True)
|
||||||
|
|
||||||
|
# Salvataggio del nuovo file dati con le colonne calcolate
|
||||||
|
print("Saving results to Hotel_Reviews_Filtered.csv")
|
||||||
|
df.to_csv(r'../data/Hotel_Reviews_Filtered.csv', index = False)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Operazioni di Analisi del Sentiment
|
||||||
|
|
||||||
|
In questa sezione finale, si applicherà l'analisi del sentiment alle colonne di recensione e si salveranno i risultati in un insieme di dati.
|
||||||
|
|
||||||
|
## Esercizio: caricare e salvare i dati filtrati
|
||||||
|
|
||||||
|
Tenere presente che ora si sta caricando l'insieme di dati filtrato che è stato salvato nella sezione precedente, **non** quello originale.
|
||||||
|
|
||||||
|
```python
|
||||||
|
import time
|
||||||
|
import pandas as pd
|
||||||
|
import nltk as nltk
|
||||||
|
from nltk.corpus import stopwords
|
||||||
|
from nltk.sentiment.vader import SentimentIntensityAnalyzer
|
||||||
|
nltk.download('vader_lexicon')
|
||||||
|
|
||||||
|
# Carica le recensioni di hotel filtrate dal CSV
|
||||||
|
df = pd.read_csv('../../data/Hotel_Reviews_Filtered.csv')
|
||||||
|
|
||||||
|
# Il proprio codice andrà aggiunto qui
|
||||||
|
|
||||||
|
|
||||||
|
# Infine ricordarsi di salvare le recensioni di hotel con i nuovi dati NLP aggiunti
|
||||||
|
print("Saving results to Hotel_Reviews_NLP.csv")
|
||||||
|
df.to_csv(r'../data/Hotel_Reviews_NLP.csv', index = False)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rimozione delle stop word
|
||||||
|
|
||||||
|
Se si dovesse eseguire l'analisi del sentiment sulle colonne delle recensioni negative e positive, potrebbe volerci molto tempo. Testato su un potente laptop di prova con CPU veloce, ci sono voluti 12 - 14 minuti a seconda della libreria di sentiment utilizzata. È un tempo (relativamente) lungo, quindi vale la pena indagare se può essere accelerato.
|
||||||
|
|
||||||
|
Il primo passo è rimuovere le stop word, o parole inglesi comuni che non cambiano il sentiment di una frase. Rimuovendole, l'analisi del sentiment dovrebbe essere eseguita più velocemente, ma non essere meno accurata (poiché le stop word non influiscono sul sentiment, ma rallentano l'analisi).
|
||||||
|
|
||||||
|
La recensione negativa più lunga è stata di 395 parole, ma dopo aver rimosso le stop word, è di 195 parole.
|
||||||
|
|
||||||
|
Anche la rimozione delle stop word è un'operazione rapida, poiché la rimozione di esse da 2 colonne di recensione su 515.000 righe ha richiesto 3,3 secondi sul dispositivo di test. Potrebbe volerci un po' più o meno tempo a seconda della velocità della CPU del proprio dispositivo, della RAM, del fatto che si abbia o meno un SSD e alcuni altri fattori. La relativa brevità dell'operazione significa che se migliora il tempo di analisi del sentiment, allora vale la pena farlo.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from nltk.corpus import stopwords
|
||||||
|
|
||||||
|
# Carica le recensioni di hotel da CSV
|
||||||
|
df = pd.read_csv("../../data/Hotel_Reviews_Filtered.csv")
|
||||||
|
|
||||||
|
# Rimuove le stop word - potrebbe essere lento quando c'è molto testo!
|
||||||
|
# Ryan Han (ryanxjhan su Kaggle) ha un gran post riguardo al misurare le prestazioni di diversi approcci per la rimozione delle stop word
|
||||||
|
# https://www.kaggle.com/ryanxjhan/fast-stop-words-removal # si usa l'approccio raccomandato da Ryan
|
||||||
|
start = time.time()
|
||||||
|
cache = set(stopwords.words("english"))
|
||||||
|
def remove_stopwords(review):
|
||||||
|
text = " ".join([word for word in review.split() if word not in cache])
|
||||||
|
return text
|
||||||
|
|
||||||
|
# Rimuove le stop word da entrambe le colonne
|
||||||
|
df.Negative_Review = df.Negative_Review.apply(remove_stopwords)
|
||||||
|
df.Positive_Review = df.Positive_Review.apply(remove_stopwords)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Esecuzione dell'analisi del sentiment
|
||||||
|
|
||||||
|
Ora si dovrebbe calcolare l'analisi del sentiment per le colonne di recensioni negative e positive e memorizzare il risultato in 2 nuove colonne. Il test del sentiment sarà quello di confrontarlo con il punteggio del recensore per la stessa recensione. Ad esempio, se il sentiment ritiene che la recensione negativa abbia avuto un sentiment pari a 1 (giudizio estremamente positivo) e un sentiment positivo della recensione pari a 1, ma il recensore ha assegnato all'hotel il punteggio più basso possibile, allora il testo della recensione non corrisponde al punteggio, oppure l'analizzatore del sentiment non è stato in grado di riconoscere correttamente il sentiment. Ci si dovrebbe aspettare che alcuni punteggi del sentiment siano completamente sbagliati, e spesso ciò sarà spiegabile, ad esempio la recensione potrebbe essere estremamente sarcastica "Certo che mi è piaciuto dormire in una stanza senza riscaldamento" e l'analizzatore del sentimento pensa che sia un sentimento positivo, anche se un un lettore umano avrebbe rilevato il sarcasmo.
|
||||||
|
|
||||||
|
NLTK fornisce diversi analizzatori di sentiment con cui imparare e si possono sostituire e vedere se il sentiment è più o meno accurato. Qui viene utilizzata l'analisi del sentiment di VADER.
|
||||||
|
|
||||||
|
> Hutto, CJ & Gilbert, EE (2014). VADER: A Parsimonious Rule-based Model for Sentiment Analysis of Social Media Text. Ottava Conferenza Internazionale su Weblog e Social Media (ICWSM-14). Ann Arbor, MI, giugno 2014.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from nltk.sentiment.vader import SentimentIntensityAnalyzer
|
||||||
|
|
||||||
|
# Crea l'analizzatore di sentiment vader (ce ne sono altri in NLTK che si possono provare)
|
||||||
|
vader_sentiment = SentimentIntensityAnalyzer()
|
||||||
|
# Hutto, C.J. & Gilbert, E.E. (2014). VADER: A Parsimonious Rule-based Model for Sentiment Analysis of Social Media Text. Eighth International Conference on Weblogs and Social Media (ICWSM-14). Ann Arbor, MI, June 2014.
|
||||||
|
|
||||||
|
# Ci sono tre possibilità di input per un recensore:
|
||||||
|
# Potrebbe essere "No Negative", nel qual caso ritorna 0
|
||||||
|
# Potrebbe essere "No Positive", nel qual caso ritorna 0
|
||||||
|
# Potrebbe essere una recensione, nel qual caso calcola il sentiment
|
||||||
|
def calc_sentiment(review):
|
||||||
|
if review == "No Negative" or review == "No Positive":
|
||||||
|
return 0
|
||||||
|
return vader_sentiment.polarity_scores(review)["compound"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Più avanti nel programma, quando si è pronti per calcolare il sentiment, lo si può applicare a ciascuna recensione come segue:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Aggiunge una colonna di sentiment negativa e positiva
|
||||||
|
print("Calculating sentiment columns for both positive and negative reviews")
|
||||||
|
start = time.time()
|
||||||
|
df["Negative_Sentiment"] = df.Negative_Review.apply(calc_sentiment)
|
||||||
|
df["Positive_Sentiment"] = df.Positive_Review.apply(calc_sentiment)
|
||||||
|
end = time.time()
|
||||||
|
print("Calculating sentiment took " + str(round(end - start, 2)) + " seconds")
|
||||||
|
```
|
||||||
|
|
||||||
|
Questo richiede circa 120 secondi sul computer utilizzato, ma varierà per ciascun computer. Se si vogliono stampare i risultati e vedere se il sentiment corrisponde alla recensione:
|
||||||
|
|
||||||
|
```python
|
||||||
|
df = df.sort_values(by=["Negative_Sentiment"], ascending=True)
|
||||||
|
print(df[["Negative_Review", "Negative_Sentiment"]])
|
||||||
|
df = df.sort_values(by=["Positive_Sentiment"], ascending=True)
|
||||||
|
print(df[["Positive_Review", "Positive_Sentiment"]])
|
||||||
|
```
|
||||||
|
|
||||||
|
L'ultima cosa da fare con il file prima di utilizzarlo nella sfida è salvarlo! Si dovrrebbe anche considerare di riordinare tutte le nuove colonne in modo che sia facile lavorarci (per un essere umano, è un cambiamento estetico).
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Riordina le colonne (E' un estetismo ma facilita l'esplorazione successiva dei dati)
|
||||||
|
df = df.reindex(["Hotel_Name", "Hotel_Address", "Total_Number_of_Reviews", "Average_Score", "Reviewer_Score", "Negative_Sentiment", "Positive_Sentiment", "Reviewer_Nationality", "Leisure_trip", "Couple", "Solo_traveler", "Business_trip", "Group", "Family_with_young_children", "Family_with_older_children", "With_a_pet", "Negative_Review", "Positive_Review"], axis=1)
|
||||||
|
|
||||||
|
print("Saving results to Hotel_Reviews_NLP.csv")
|
||||||
|
df.to_csv(r"../data/Hotel_Reviews_NLP.csv", index = False)
|
||||||
|
```
|
||||||
|
|
||||||
|
Si dovrebbe eseguire l'intero codice per [il notebook di analisi](../solution/3-notebook.ipynb) (dopo aver eseguito [il notebook di filtraggio](../solution/1-notebook.ipynb) per generare il file Hotel_Reviews_Filtered.csv).
|
||||||
|
|
||||||
|
Per riepilogare, i passaggi sono:
|
||||||
|
|
||||||
|
1. Il file del'insieme di dati originale **Hotel_Reviews.csv** è stato esplorato nella lezione precedente con [il notebook explorer](../../4-Hotel-Reviews-1/solution/notebook.ipynb)
|
||||||
|
2. Hotel_Reviews.csv viene filtrato [dal notebook di filtraggio](../solution/1-notebook.ipynb) risultante in **Hotel_Reviews_Filtered.csv**
|
||||||
|
3. Hotel_Reviews_Filtered.csv viene elaborato dal [notebook di analisi del sentiment](../solution/3-notebook.ipynb) risultante in **Hotel_Reviews_NLP.csv**
|
||||||
|
4. Usare Hotel_Reviews_NLP.csv nella Sfida NLP di seguito
|
||||||
|
|
||||||
|
### Conclusione
|
||||||
|
|
||||||
|
Quando si è iniziato, si disponeva di un insieme di dati con colonne e dati, ma non tutto poteva essere verificato o utilizzato. Si sono esplorati i dati, filtrato ciò che non serve, convertito i tag in qualcosa di utile, calcolato le proprie medie, aggiunto alcune colonne di sentiment e, si spera, imparato alcune cose interessanti sull'elaborazione del testo naturale.
|
||||||
|
|
||||||
|
## [Quiz post-lezione](https://jolly-sea-0a877260f.azurestaticapps.net/quiz/40/)
|
||||||
|
|
||||||
|
## Sfida
|
||||||
|
|
||||||
|
Ora che si è analizzato il proprio insieme di dati per il sentiment, vedere se si possono usare le strategie apprese in questo programma di studi (clustering, forse?) per determinare modelli intorno al sentiment.
|
||||||
|
|
||||||
|
## recensione e Auto Apprendimento
|
||||||
|
|
||||||
|
Seguire [questo modulo di apprendimento](https://docs.microsoft.com/en-us/learn/modules/classify-user-feedback-with-the-text-analytics-api/?WT.mc_id=academic-15963-cxa) per saperne di più e utilizzare diversi strumenti per esplorare il sentiment nel testo.
|
||||||
|
|
||||||
|
## Compito
|
||||||
|
|
||||||
|
[Provare un insieme di dati diverso](assignment.it.md)
|
@ -0,0 +1,11 @@
|
|||||||
|
# Provare un insieme di dati diverso
|
||||||
|
|
||||||
|
## Istruzioni
|
||||||
|
|
||||||
|
Ora che si è imparato a usare NLTK per assegnare sentiment al testo, provare un insieme di dati diverso. Probabilmente si dovranno elaborare dei dati attorno ad esso, quindi creare un notebook e documentare il proprio processo di pensiero. Cosa si è scoperto?
|
||||||
|
|
||||||
|
## Rubrica
|
||||||
|
|
||||||
|
| Criteri | Ottimo | Adeguato | Necessita miglioramento |
|
||||||
|
| -------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | ---------------------- |
|
||||||
|
| | Vengono presentati un notebook completo e un insieme di dati con celle ben documentate che spiegano come viene assegnato il sentiment | Il notebook manca di buone spiegazioni | Il notebook è difettoso |
|
@ -0,0 +1,24 @@
|
|||||||
|
# Iniziare con l'elaborazione del linguaggio naturale
|
||||||
|
|
||||||
|
L'elaborazione del linguaggio naturale, NLP, è un sottocampo dell'intelligenza artificiale. L'intero campo è volto ad aiutare le macchine a comprendere ed elaborare il linguaggio umano. Questo può quindi essere utilizzato per eseguire attività come il controllo ortografico o la traduzione automatica.
|
||||||
|
|
||||||
|
## Argomento regionale: lingue e letterature europee e hotel romantici d'Europa ❤️
|
||||||
|
|
||||||
|
In questa sezione del programma di studi, verrà presentato uno degli usi più diffusi di machine learning: l'elaborazione del linguaggio naturale (NLP). Derivato dalla linguistica computazionale, questa categoria di intelligenza artificiale è il ponte tra umani e macchine tramite la comunicazione vocale o testuale.
|
||||||
|
|
||||||
|
In queste lezioni si impareranno le basi di NLP costruendo piccoli bot conversazionali per imparare come machine learning aiuti a rendere queste conversazioni sempre più "intelligenti". Si viaggerà indietro nel tempo, chiacchierando con Elizabeth Bennett e Mr. Darcy dal romanzo classico di Jane Austen, **Orgoglio e pregiudizio**, pubblicato nel 1813. Quindi, si approfondiranno le proprie conoscenze imparando l'analisi del sentiment tramite le recensioni di hotel in Europa.
|
||||||
|
|
||||||
|
![Libro e tè di Orgoglio e Pregiudizio](../images/p&p.jpg)
|
||||||
|
> Foto di <a href="https://unsplash.com/@elaineh?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Elaine Howlin</a> su <a href="https://unsplash.com/s/photos/pride-and-prejudice?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
|
||||||
|
|
||||||
|
## Lezioni
|
||||||
|
|
||||||
|
1. [Introduzione all'elaborazione del linguaggio naturale](../1-Introduction-to-NLP/translations/README.it.md)
|
||||||
|
2. [Compiti e tecniche comuni di NLP](../2-Tasks/translations/README.it.md)
|
||||||
|
3. [Traduzione e analisi del sentiment con machine learning](../3-Translation-Sentiment/translations/README.it.md)
|
||||||
|
4. [Preparazione dei dati](../4-Hotel-Reviews-1/translations/README.it.md)
|
||||||
|
5. [NLTK per l'analisi del sentiment](../5-Hotel-Reviews-2/translations/README.it.md)
|
||||||
|
|
||||||
|
## Crediti
|
||||||
|
|
||||||
|
Queste lezioni sull'elaborazione del linguaggio naturale sono state scritte con ☕ da [Stephen Howell](https://twitter.com/Howell_MSFT)
|
Loading…
Reference in new issue