AI FÖR NATURLIGT SPRÅK

Kursinfo

Kursmaterial

FAQ

Kursmaterial

/

Kapitel

Deluppgift 2: Sentimentanalys

Att skapa en baseline

Följande filer används i uppgiften:

app_sentiment.csv - Recensioner av applikationer från Google Play Store.

För att spara filerna, högerklicka på länken och välj att spara filen. Du behöver inte ladda ned några filer för att genomföra uppgiften, utan de är per automatik tillgängliga för användning i kodcellerna nedan.


I denna deluppgift ska vi utföra sentimentanalys och vi kommer använda oss av samma dataset som i Deluppgift 1. Tanken är att recensioner med negativ innebörd (klassen neg) har egenskaper som skiljer sig från de med positiv innebörd (klassen pos), därmed kan vi träna modeller som kan särskilja på de två klasserna.

Vi börjar med att läsa in vår data igen, på samma sätt som i förra uppgiften, och delar upp den i tränings- och testset. Eftersom random_state har samma värde så kommer vi få en exakt likadan fördelning av data som i föregående uppgift.

Det första steget när vi ska utveckla modeller är att ta fram en baseline. En baseline är ofta en mycket enkel modell – den kan vara resultatet om en modell hade valt klasser slumpmässigt eller den klass som förekommer oftast. Detta är “dumma” modeller som vi alltid vill kunna överträffa när vi bygger “smarta” modeller. Att träna och utvärdera modeller utan att ha en baseline kan liknas vid att hoppa höjdhopp utan att ha ribba: vi kan se att vissa modeller är bättre än andra, men det är svårt att bedöma om de är bra.

I följande kodcell vill vi ta fram en baseline-modell som för varje exempel i test-data gissar på den mest frekventa klassen. Scikit-learn ger oss möjlighet att enkelt skapa en baseline med DummyClassifier. Du behöver ta reda på vilka argument som DummyClassifier ska ta in för att den ska klassificera efter “mest frekventa klassen”-metoden.

Funktionen fit() tränar på träningsdata i den meningen att den tar reda på vilken klass som är den mest frekventa, och predict() returnerar den mest frekventa klassen för varje recension i testdata.

Ett användbart verktyg för att utvärdera vår modell är en förväxlingsmatris. Den presenterar hur modellens klassificeringar förhåller sig till de sanna värdena från testdata. Raderna indikerar det sanna värdet och kolumnerna modellens klassificering.

För att ta fram en förväxlingsmatris använder vi oss av confusion_matrix() från Scikit-learn. Du ska använda pred_mfc och de sanna värderna från testdata för att skapa förväxlingsmatrisen.

Vi kan utläsa från förväxlingsmatrisen att vår modell alltid returnerar klassen pos, vilket är vad vi förväntar oss då det också är den mest frekventa klassen.

För att få en mer nyanserad bild av hur väl vår modell presterar så vill vi ta fram recall, precision och F1-värdet. Detta går att räkna ut från vår förväxlingsmatris, men det finns självklart funktionalitet från Scikit-learn som vi kan använda oss av, nämligen funktionen classification_report().

I följande uppgift ska du använda classification_report() för att generera information så att vi kan utvärdera modellen.

Detta är värdena som vi vill jämföra med när vi skapar nya modeller.

Naive Bayes

Nu ska vi träna och utvärdera en Naive Bayes-modell. För att klassificera använder Naive Bayes sig av sannolikheten att ord i en text förknippas med en specifik klass och hur sannolikt det är att den klassen förekommer i vår data.

Vi använder oss av MultinomialNB från Scikit-learn för att skapa vår modell. (Det finns ofta flera inställningar till modellen som kan förbättra/försämra dess resultat givet ett visst dataset. Du får gärna själv läsa dokumentationen och experimentera med olika värden på argument till modellen).

För att kunna träna modellen behöver vi ta fram hur ofta ord förekommer i en text. I Naive Bayes används det för att ta reda på hur sannolikt det är för ett visst ord att tillhöra klasserna. CountVectorizer transformerar en text till en representation där varje mening blir en vektor som representerar hur ofta orden i meningen förekommer.

I nästa kodcell skapas en CountVectorizer och en klassificerare av typen MultinomialNB. Ett exempel bestående av tre meningar vektoriseras och sedan skrivs varje ord ut (med deras index) och meningarnas vektorer.

Nu vill vi transformera alla recensioner i vårt dataset från text till vektorer som representerar ordens frekvens. När all textdata blivit vektoriserad ska den sedan användas för att träna vår Naive Bayes-modell med funktionen fit(). fit() kommer ta in de vektoriserade recensionerna och den klass som de tillhör, d.v.s. varje tillhörande rating. Din uppgift är att ge vektoriseraren och funktionen fit() rätt argument för att träna modellen.

Modellen har tränat klart och vi kan nu tillämpa och utvärdera modellen på testdata.

Du behöver nu vektorisera recensionerna i testdata och ge dem som argument till modellens funktion predict(), som gör vad namnet förtäljer: för varje exempel i testdata kommer modellen returnera en av våra två klasser, pos eller neg. Funktionen returnerar en lista med klassificeringarna.

Bara från urvalet kan vi se ett resultat som skiljer sig från baseline. Frågan nu är bara om det är ett bättre resultat.

För att ta reda på detta ska du ta fram en förväxlingsmatris på samma sätt som när baseline utvärderades:

Vi ser en tydlig skillnad mot baseline i att modell oftare klassificerar neg när det korrekta resultatet är neg. Vi kan dock se det finns en förväxling mellan pos och neg, och du ska därför tar fram en klassifikationsrapport för att få en tydligare bild av modellens precision, recall och F1-värde.

Där har vi tränat vår första riktiga modell, och vi kan se en tydlig förbättring mot baseline!

Innan vi lämnar denna deluppgiften så ska vi kika på ett verktyg i Scikit-learn som kallas Pipeline. Den ger oss möjligheten att bygga något som kan likna en produktionslinje: all data som går in i vår pipeline behöver passera vissa funktioner för att transformeras. I en pipeline kan vi säga att all data först ska transformeras av en vektoriserare och sedan användas av en specifik modell. När data sedan skickas in som argument till en funktion som fit() kommer denna data att gå igenom vår pipeline (först vektoriseras och sedan användas för att träna modellen.) Pipelines kan därför förenkla vårt arbetssätt, och vi kommer fortsätta att använda dem i detta kapitlet.

I nästa kodcell ges ett exempel på hur vi kan använda pipelines för att genomföra samma uppgifter som i cellerna ovan.

Något vi kan observera är att vår modell är mer benägen att gissa på den klass som förekommer oftast i vår träningsdata. Detta kan leda till att modellen inte generaliserar lika väl till data där fördelningen mellan klasserna ser annorlunda ut. I nästa deluppgift ska vi kika på hur vi kan balansera data för att göra vår modell mer generaliserbar.

Denna webbsajt innehåller kursmaterialet för kursen ETE335 AI för naturligt språk.
Materialet är licenserat under en Creative Commons Erkännande 4.0 Internationell licens.
Copyright © 2022, Marco Kuhlmann & Oskar Holmström