35 KiB
Sentimentanalyse met hotelbeoordelingen - gegevens verwerken
In deze sectie gebruik je de technieken uit de vorige lessen om een verkennende gegevensanalyse uit te voeren op een grote dataset. Zodra je een goed begrip hebt van de bruikbaarheid van de verschillende kolommen, leer je:
- hoe je onnodige kolommen kunt verwijderen
- hoe je nieuwe gegevens kunt berekenen op basis van bestaande kolommen
- hoe je de resulterende dataset kunt opslaan voor gebruik in de laatste uitdaging
Pre-lecture quiz
Introductie
Tot nu toe heb je geleerd dat tekstgegevens heel anders zijn dan numerieke gegevens. Als het tekst is die door een mens is geschreven of gesproken, kan het worden geanalyseerd om patronen en frequenties, sentiment en betekenis te vinden. Deze les introduceert je in een echte dataset met een echte uitdaging: 515K Hotel Reviews Data in Europe, inclusief een CC0: Public Domain-licentie. De gegevens zijn afkomstig van Booking.com en verzameld uit openbare bronnen. De maker van de dataset is Jiashen Liu.
Voorbereiding
Wat je nodig hebt:
- De mogelijkheid om .ipynb-notebooks uit te voeren met Python 3
- pandas
- NLTK, dat je lokaal moet installeren
- De dataset, beschikbaar op Kaggle: 515K Hotel Reviews Data in Europe. Het bestand is ongeveer 230 MB uitgepakt. Download het naar de root
/data
map die bij deze NLP-lessen hoort.
Verkennende gegevensanalyse
Deze uitdaging gaat ervan uit dat je een hotelaanbevelingsbot bouwt met behulp van sentimentanalyse en gastbeoordelingsscores. De dataset die je gebruikt bevat beoordelingen van 1493 verschillende hotels in 6 steden.
Met Python, een dataset van hotelbeoordelingen en de sentimentanalyse van NLTK kun je ontdekken:
- Wat zijn de meest gebruikte woorden en zinnen in beoordelingen?
- Correleren de officiële tags die een hotel beschrijven met beoordelingsscores (bijvoorbeeld: zijn er meer negatieve beoordelingen voor een bepaald hotel van Gezin met jonge kinderen dan van Solo reiziger, wat misschien aangeeft dat het beter geschikt is voor Solo reizigers)?
- Stemmen de sentiment scores van NLTK overeen met de numerieke score van de hotelbeoordelaar?
Dataset
Laten we de dataset verkennen die je hebt gedownload en lokaal hebt opgeslagen. Open het bestand in een editor zoals VS Code of zelfs Excel.
De headers in de dataset zijn als volgt:
Hotel_Address, Additional_Number_of_Scoring, Review_Date, Average_Score, Hotel_Name, Reviewer_Nationality, Negative_Review, Review_Total_Negative_Word_Counts, Total_Number_of_Reviews, Positive_Review, Review_Total_Positive_Word_Counts, Total_Number_of_Reviews_Reviewer_Has_Given, Reviewer_Score, Tags, days_since_review, lat, lng
Hier zijn ze gegroepeerd op een manier die gemakkelijker te onderzoeken is:
Hotelkolommen
Hotel_Name
,Hotel_Address
,lat
(breedtegraad),lng
(lengtegraad)- Met lat en lng kun je een kaart plotten met Python die de hotel locaties toont (misschien kleurgecodeerd voor negatieve en positieve beoordelingen)
- Hotel_Address is niet direct nuttig voor ons, en we zullen dat waarschijnlijk vervangen door een land voor gemakkelijker sorteren en zoeken
Hotel Meta-review kolommen
-
Average_Score
- Volgens de datasetmaker is deze kolom de Gemiddelde score van het hotel, berekend op basis van de laatste opmerking in het afgelopen jaar. Dit lijkt een ongebruikelijke manier om de score te berekenen, maar het zijn de verzamelde gegevens, dus we nemen het voorlopig voor waar aan.
✅ Kun je op basis van de andere kolommen in deze dataset een andere manier bedenken om de gemiddelde score te berekenen?
-
Total_Number_of_Reviews
- Het totale aantal beoordelingen dat dit hotel heeft ontvangen - het is niet duidelijk (zonder code te schrijven) of dit verwijst naar de beoordelingen in de dataset.
-
Additional_Number_of_Scoring
- Dit betekent dat er een beoordelingsscore is gegeven, maar geen positieve of negatieve beoordeling is geschreven door de beoordelaar.
Beoordelingskolommen
Reviewer_Score
- Dit is een numerieke waarde met maximaal 1 decimaal tussen de minimum- en maximumwaarden 2.5 en 10
- Het is niet uitgelegd waarom 2.5 de laagst mogelijke score is
Negative_Review
- Als een beoordelaar niets heeft geschreven, bevat dit veld "No Negative"
- Merk op dat een beoordelaar een positieve beoordeling kan schrijven in de kolom Negative review (bijvoorbeeld: "er is niets slechts aan dit hotel")
Review_Total_Negative_Word_Counts
- Hogere negatieve woordenaantallen duiden op een lagere score (zonder de sentimentanalyse te controleren)
Positive_Review
- Als een beoordelaar niets heeft geschreven, bevat dit veld "No Positive"
- Merk op dat een beoordelaar een negatieve beoordeling kan schrijven in de kolom Positive review (bijvoorbeeld: "er is helemaal niets goeds aan dit hotel")
Review_Total_Positive_Word_Counts
- Hogere positieve woordenaantallen duiden op een hogere score (zonder de sentimentanalyse te controleren)
Review_Date
endays_since_review
- Een maatstaf voor versheid of veroudering kan worden toegepast op een beoordeling (oudere beoordelingen zijn mogelijk minder accuraat dan nieuwere omdat het hotelmanagement is veranderd, er renovaties zijn uitgevoerd, of er een zwembad is toegevoegd, etc.)
Tags
- Dit zijn korte beschrijvingen die een beoordelaar kan selecteren om het type gast dat ze waren te beschrijven (bijvoorbeeld solo of gezin), het type kamer dat ze hadden, de duur van het verblijf en hoe de beoordeling is ingediend.
- Helaas is het gebruik van deze tags problematisch, zie de sectie hieronder die hun bruikbaarheid bespreekt.
Beoordelaar kolommen
Total_Number_of_Reviews_Reviewer_Has_Given
- Dit kan een factor zijn in een aanbevelingsmodel, bijvoorbeeld als je kunt bepalen dat meer productieve beoordelaars met honderden beoordelingen eerder negatief dan positief zijn. Echter, de beoordelaar van een specifieke beoordeling wordt niet geïdentificeerd met een unieke code, en kan daarom niet worden gekoppeld aan een set beoordelingen. Er zijn 30 beoordelaars met 100 of meer beoordelingen, maar het is moeilijk te zien hoe dit het aanbevelingsmodel kan helpen.
Reviewer_Nationality
- Sommige mensen denken misschien dat bepaalde nationaliteiten eerder een positieve of negatieve beoordeling geven vanwege een nationale neiging. Wees voorzichtig met het opnemen van dergelijke anekdotische opvattingen in je modellen. Dit zijn nationale (en soms raciale) stereotypen, en elke beoordelaar was een individu die een beoordeling schreef op basis van hun ervaring. Dit kan zijn gefilterd door vele lenzen zoals hun eerdere hotelverblijven, de afgelegde afstand en hun persoonlijke temperament. Denken dat hun nationaliteit de reden was voor een beoordelingsscore is moeilijk te rechtvaardigen.
Voorbeelden
Gemiddelde Score | Totaal aantal beoordelingen | Beoordelaar Score | Negatieve Beoordeling |
Positieve Beoordeling | Tags |
---|---|---|---|---|---|
7.8 | 1945 | 2.5 | Dit is momenteel geen hotel maar een bouwplaats. Ik werd van vroeg in de ochtend tot de hele dag geterroriseerd door onacceptabel bouwlawaai terwijl ik probeerde uit te rusten na een lange reis en werken in de kamer. Mensen werkten de hele dag, bijvoorbeeld met drilboren in de aangrenzende kamers. Ik vroeg om een kamerwissel, maar er was geen stille kamer beschikbaar. Om het nog erger te maken, werd ik te veel in rekening gebracht. Ik checkte 's avonds uit omdat ik een vroege vlucht had en kreeg een passende rekening. Een dag later maakte het hotel een andere afschrijving zonder mijn toestemming bovenop de geboekte prijs. Het is een vreselijke plek. Straf jezelf niet door hier te boeken. | Niets. Vreselijke plek. Blijf weg. | Zakenreis Koppel Standaard Tweepersoonskamer Verbleef 2 nachten |
Zoals je kunt zien, had deze gast geen prettig verblijf in dit hotel. Het hotel heeft een goede gemiddelde score van 7.8 en 1945 beoordelingen, maar deze beoordelaar gaf het een 2.5 en schreef 115 woorden over hoe negatief hun verblijf was. Als ze niets hadden geschreven in de kolom Positive_Review, zou je kunnen concluderen dat er niets positiefs was, maar ze schreven toch 7 waarschuwende woorden. Als we alleen woorden zouden tellen in plaats van de betekenis of het sentiment van de woorden, zouden we een vertekend beeld kunnen krijgen van de intentie van de beoordelaar. Vreemd genoeg is hun score van 2.5 verwarrend, want als dat hotelverblijf zo slecht was, waarom dan überhaupt punten geven? Bij nader onderzoek van de dataset zul je zien dat de laagst mogelijke score 2.5 is, niet 0. De hoogst mogelijke score is 10.
Tags
Zoals hierboven vermeld, lijkt het idee om Tags
te gebruiken om de gegevens te categoriseren in eerste instantie logisch. Helaas zijn deze tags niet gestandaardiseerd, wat betekent dat in een bepaald hotel de opties Eenpersoonskamer, Tweepersoonskamer en Dubbele kamer kunnen zijn, maar in het volgende hotel zijn ze Deluxe Eenpersoonskamer, Classic Queen Kamer en Executive King Kamer. Dit kunnen dezelfde dingen zijn, maar er zijn zoveel variaties dat de keuze wordt:
-
Proberen alle termen te veranderen naar een enkele standaard, wat erg moeilijk is, omdat het niet duidelijk is wat het conversiepad in elk geval zou zijn (bijvoorbeeld: Classic eenpersoonskamer wordt Eenpersoonskamer, maar Superior Queen Kamer met Binnenplaats Tuin of Uitzicht op de Stad is veel moeilijker te mappen)
-
We kunnen een NLP-aanpak nemen en de frequentie meten van bepaalde termen zoals Solo, Zakelijke Reiziger of Gezin met jonge kinderen zoals ze van toepassing zijn op elk hotel, en dat meenemen in de aanbeveling.
Tags zijn meestal (maar niet altijd) een enkel veld dat een lijst bevat van 5 tot 6 komma-gescheiden waarden die overeenkomen met Type reis, Type gasten, Type kamer, Aantal nachten en Type apparaat waarop de beoordeling is ingediend. Omdat sommige beoordelaars echter niet elk veld invullen (ze kunnen er een leeg laten), zijn de waarden niet altijd in dezelfde volgorde.
Als voorbeeld, neem Type groep. Er zijn 1025 unieke mogelijkheden in dit veld in de Tags
kolom, en helaas verwijzen slechts enkele naar een groep (sommige zijn het type kamer, etc.). Als je alleen filtert op de waarden die familie vermelden, bevatten de resultaten veel Familiekamer type resultaten. Als je de term met opneemt, bijvoorbeeld de waarden Gezin met, zijn de resultaten beter, met meer dan 80.000 van de 515.000 resultaten die de zinsnede "Gezin met jonge kinderen" of "Gezin met oudere kinderen" bevatten.
Dit betekent dat de tags-kolom niet volledig nutteloos is, maar het zal wat werk kosten om het bruikbaar te maken.
Gemiddelde hotelscore
Er zijn een aantal eigenaardigheden of discrepanties in de dataset die ik niet kan verklaren, maar die hier worden geïllustreerd zodat je je ervan bewust bent bij het bouwen van je modellen. Als je het uitvindt, laat het ons weten in de discussiesectie!
De dataset heeft de volgende kolommen met betrekking tot de gemiddelde score en het aantal beoordelingen:
- Hotel_Name
- Additional_Number_of_Scoring
- Average_Score
- Total_Number_of_Reviews
- Reviewer_Score
Het hotel met de meeste beoordelingen in deze dataset is Britannia International Hotel Canary Wharf met 4789 beoordelingen van de 515.000. Maar als we kijken naar de waarde Total_Number_of_Reviews
voor dit hotel, is dat 9086. Je zou kunnen concluderen dat er veel meer scores zijn zonder beoordelingen, dus misschien moeten we de waarde in de kolom Additional_Number_of_Scoring
toevoegen. Die waarde is 2682, en als we die optellen bij 4789 krijgen we 7471, wat nog steeds 1615 tekortschiet ten opzichte van Total_Number_of_Reviews
.
Als je de kolom Average_Score
neemt, zou je kunnen concluderen dat dit het gemiddelde is van de beoordelingen in de dataset, maar de beschrijving van Kaggle is "Gemiddelde score van het hotel, berekend op basis van de laatste opmerking in het afgelopen jaar". Dat lijkt niet zo nuttig, maar we kunnen ons eigen gemiddelde berekenen op basis van de beoordelingsscores in de dataset. Als we hetzelfde hotel als voorbeeld nemen, wordt de gemiddelde hotelscore gegeven als 7.1, maar de berekende score (gemiddelde beoordelaarsscore in de dataset) is 6.8. Dit is dichtbij, maar niet dezelfde waarde, en we kunnen alleen maar raden dat de scores in de Additional_Number_of_Scoring
beoordelingen het gemiddelde verhoogden naar 7.1. Helaas, zonder een manier om die bewering te testen of te bewijzen, is het moeilijk om Average_Score
, Additional_Number_of_Scoring
en Total_Number_of_Reviews
te gebruiken of te vertrouwen wanneer ze gebaseerd zijn op, of verwijzen naar, gegevens die we niet hebben.
Om het nog ingewikkelder te maken, heeft het hotel met het op één na hoogste aantal beoordelingen een berekende gemiddelde score van 8.12 en de dataset Average_Score
is 8.1. Is deze correcte score toeval of is het eerste hotel een discrepantie?
Op basis van de mogelijkheid dat deze hotels een uitschieter zijn, en dat misschien de meeste waarden wel kloppen (maar sommige om een of andere reden niet), zullen we in de volgende stap een kort programma schrijven om de waarden in de dataset te verkennen en het juiste gebruik (of niet-gebruik) van de waarden te bepalen.
🚨 Een waarschuwing
Bij het werken met deze dataset schrijf je code die iets berekent op basis van de tekst, zonder dat je de tekst zelf hoeft te lezen of te analyseren. Dit is de kern van NLP: betekenis of sentiment interpreteren zonder dat een mens dit hoeft te doen. Het is echter mogelijk dat je enkele negatieve beoordelingen zult lezen. Ik raad je aan dit niet te doen, omdat het niet nodig is. Sommige van deze beoordelingen zijn onzinnig of irrelevante negatieve hotelbeoordelingen, zoals "Het weer was niet goed", iets wat buiten de controle van het hotel, of eigenlijk van iedereen, ligt. Maar er is ook een donkere kant aan sommige beoordelingen. Soms zijn de negatieve beoordelingen racistisch, seksistisch of discriminerend op basis van leeftijd. Dit is jammer, maar te verwachten in een dataset die van een openbare website is gehaald. Sommige reviewers laten beoordelingen achter die je smakeloos, ongemakkelijk of verontrustend zou kunnen vinden. Het is beter om de code het sentiment te laten meten dan ze zelf te lezen en van streek te raken. Dat gezegd hebbende, het is een minderheid die dergelijke dingen schrijft, maar ze bestaan wel degelijk.
Oefening - Data verkennen
Laad de data
Dat is genoeg visueel onderzoek naar de data, nu ga je wat code schrijven en antwoorden krijgen! Dit gedeelte maakt gebruik van de pandas-bibliotheek. Je eerste taak is ervoor te zorgen dat je de CSV-data kunt laden en lezen. De pandas-bibliotheek heeft een snelle CSV-loader, en het resultaat wordt geplaatst in een dataframe, zoals in eerdere lessen. De CSV die we laden heeft meer dan een half miljoen rijen, maar slechts 17 kolommen. Pandas biedt veel krachtige manieren om met een dataframe te werken, waaronder de mogelijkheid om bewerkingen op elke rij uit te voeren.
Vanaf hier in deze les zullen er codefragmenten zijn, enkele uitleg over de code en discussies over wat de resultaten betekenen. Gebruik het meegeleverde notebook.ipynb voor je code.
Laten we beginnen met het laden van het databestand dat je gaat gebruiken:
# Load the hotel reviews from CSV
import pandas as pd
import time
# importing time so the start and end time can be used to calculate file loading time
print("Loading data file now, this could take a while depending on file size")
start = time.time()
# df is 'DataFrame' - make sure you downloaded the file to the data folder
df = pd.read_csv('../../data/Hotel_Reviews.csv')
end = time.time()
print("Loading took " + str(round(end - start, 2)) + " seconds")
Nu de data is geladen, kunnen we enkele bewerkingen uitvoeren. Houd deze code bovenaan je programma voor het volgende deel.
Verken de data
In dit geval is de data al schoon, wat betekent dat het klaar is om mee te werken en geen tekens in andere talen bevat die algoritmes, die alleen Engelse tekens verwachten, in de war kunnen brengen.
✅ Je zou kunnen werken met data die enige initiële verwerking vereist om het te formatteren voordat je NLP-technieken toepast, maar dat is deze keer niet nodig. Als je dat wel moest doen, hoe zou je omgaan met niet-Engelse tekens?
Neem even de tijd om ervoor te zorgen dat je, zodra de data is geladen, deze met code kunt verkennen. Het is heel verleidelijk om je te richten op de kolommen Negative_Review
en Positive_Review
. Ze zijn gevuld met natuurlijke tekst voor je NLP-algoritmes om te verwerken. Maar wacht! Voordat je begint met NLP en sentimentanalyse, moet je de onderstaande code volgen om te controleren of de waarden in de dataset overeenkomen met de waarden die je berekent met pandas.
Dataframe-bewerkingen
De eerste taak in deze les is om te controleren of de volgende aannames correct zijn door code te schrijven die het dataframe onderzoekt (zonder het te wijzigen).
Zoals bij veel programmeertaken zijn er meerdere manieren om dit te voltooien, maar een goed advies is om het op de eenvoudigste, gemakkelijkste manier te doen, vooral als het gemakkelijker te begrijpen is wanneer je later naar deze code terugkeert. Met dataframes is er een uitgebreide API die vaak een efficiënte manier biedt om te doen wat je wilt.
Behandel de volgende vragen als codetaken en probeer ze te beantwoorden zonder naar de oplossing te kijken.
- Print de shape van het dataframe dat je zojuist hebt geladen (de shape is het aantal rijen en kolommen).
- Bereken de frequentie van recensent-nationaliteiten:
- Hoeveel unieke waarden zijn er in de kolom
Reviewer_Nationality
en wat zijn ze? - Welke recensent-nationaliteit komt het meest voor in de dataset (print land en aantal recensies)?
- Wat zijn de volgende top 10 meest voorkomende nationaliteiten en hun frequentie?
- Hoeveel unieke waarden zijn er in de kolom
- Wat was het meest beoordeelde hotel voor elk van de top 10 meest voorkomende recensent-nationaliteiten?
- Hoeveel recensies zijn er per hotel (frequentie van hotel) in de dataset?
- Hoewel er een kolom
Average_Score
is voor elk hotel in de dataset, kun je ook een gemiddelde score berekenen (het gemiddelde van alle recensent-scores in de dataset voor elk hotel). Voeg een nieuwe kolom toe aan je dataframe met de kolomkopCalc_Average_Score
die dat berekende gemiddelde bevat. - Hebben hotels dezelfde (afgerond op 1 decimaal)
Average_Score
enCalc_Average_Score
?- Probeer een Python-functie te schrijven die een Series (rij) als argument neemt en de waarden vergelijkt, en een bericht print wanneer de waarden niet gelijk zijn. Gebruik vervolgens de
.apply()
-methode om elke rij met de functie te verwerken.
- Probeer een Python-functie te schrijven die een Series (rij) als argument neemt en de waarden vergelijkt, en een bericht print wanneer de waarden niet gelijk zijn. Gebruik vervolgens de
- Bereken en print hoeveel rijen de waarde "No Negative" hebben in de kolom
Negative_Review
. - Bereken en print hoeveel rijen de waarde "No Positive" hebben in de kolom
Positive_Review
. - Bereken en print hoeveel rijen de waarde "No Positive" hebben in de kolom
Positive_Review
en de waarde "No Negative" in de kolomNegative_Review
.
Code-antwoorden
-
Print de shape van het dataframe dat je zojuist hebt geladen (de shape is het aantal rijen en kolommen).
print("The shape of the data (rows, cols) is " + str(df.shape)) > The shape of the data (rows, cols) is (515738, 17)
-
Bereken de frequentie van recensent-nationaliteiten:
- Hoeveel unieke waarden zijn er in de kolom
Reviewer_Nationality
en wat zijn ze? - Welke recensent-nationaliteit komt het meest voor in de dataset (print land en aantal recensies)?
# value_counts() creates a Series object that has index and values in this case, the country and the frequency they occur in reviewer nationality nationality_freq = df["Reviewer_Nationality"].value_counts() print("There are " + str(nationality_freq.size) + " different nationalities") # print first and last rows of the Series. Change to nationality_freq.to_string() to print all of the data print(nationality_freq) There are 227 different nationalities United Kingdom 245246 United States of America 35437 Australia 21686 Ireland 14827 United Arab Emirates 10235 ... Comoros 1 Palau 1 Northern Mariana Islands 1 Cape Verde 1 Guinea 1 Name: Reviewer_Nationality, Length: 227, dtype: int64
-
Wat zijn de volgende top 10 meest voorkomende nationaliteiten en hun frequentie?
print("The highest frequency reviewer nationality is " + str(nationality_freq.index[0]).strip() + " with " + str(nationality_freq[0]) + " reviews.") # Notice there is a leading space on the values, strip() removes that for printing # What is the top 10 most common nationalities and their frequencies? print("The next 10 highest frequency reviewer nationalities are:") print(nationality_freq[1:11].to_string()) The highest frequency reviewer nationality is United Kingdom with 245246 reviews. The next 10 highest frequency reviewer nationalities are: United States of America 35437 Australia 21686 Ireland 14827 United Arab Emirates 10235 Saudi Arabia 8951 Netherlands 8772 Switzerland 8678 Germany 7941 Canada 7894 France 7296
- Hoeveel unieke waarden zijn er in de kolom
-
Wat was het meest beoordeelde hotel voor elk van de top 10 meest voorkomende recensent-nationaliteiten?
# What was the most frequently reviewed hotel for the top 10 nationalities # Normally with pandas you will avoid an explicit loop, but wanted to show creating a new dataframe using criteria (don't do this with large amounts of data because it could be very slow) for nat in nationality_freq[:10].index: # First, extract all the rows that match the criteria into a new dataframe nat_df = df[df["Reviewer_Nationality"] == nat] # Now get the hotel freq freq = nat_df["Hotel_Name"].value_counts() print("The most reviewed hotel for " + str(nat).strip() + " was " + str(freq.index[0]) + " with " + str(freq[0]) + " reviews.") The most reviewed hotel for United Kingdom was Britannia International Hotel Canary Wharf with 3833 reviews. The most reviewed hotel for United States of America was Hotel Esther a with 423 reviews. The most reviewed hotel for Australia was Park Plaza Westminster Bridge London with 167 reviews. The most reviewed hotel for Ireland was Copthorne Tara Hotel London Kensington with 239 reviews. The most reviewed hotel for United Arab Emirates was Millennium Hotel London Knightsbridge with 129 reviews. The most reviewed hotel for Saudi Arabia was The Cumberland A Guoman Hotel with 142 reviews. The most reviewed hotel for Netherlands was Jaz Amsterdam with 97 reviews. The most reviewed hotel for Switzerland was Hotel Da Vinci with 97 reviews. The most reviewed hotel for Germany was Hotel Da Vinci with 86 reviews. The most reviewed hotel for Canada was St James Court A Taj Hotel London with 61 reviews.
-
Hoeveel recensies zijn er per hotel (frequentie van hotel) in de dataset?
# First create a new dataframe based on the old one, removing the uneeded columns hotel_freq_df = df.drop(["Hotel_Address", "Additional_Number_of_Scoring", "Review_Date", "Average_Score", "Reviewer_Nationality", "Negative_Review", "Review_Total_Negative_Word_Counts", "Positive_Review", "Review_Total_Positive_Word_Counts", "Total_Number_of_Reviews_Reviewer_Has_Given", "Reviewer_Score", "Tags", "days_since_review", "lat", "lng"], axis = 1) # Group the rows by Hotel_Name, count them and put the result in a new column Total_Reviews_Found hotel_freq_df['Total_Reviews_Found'] = hotel_freq_df.groupby('Hotel_Name').transform('count') # Get rid of all the duplicated rows hotel_freq_df = hotel_freq_df.drop_duplicates(subset = ["Hotel_Name"]) display(hotel_freq_df)
Hotel_Name Total_Number_of_Reviews Total_Reviews_Found Britannia International Hotel Canary Wharf 9086 4789 Park Plaza Westminster Bridge London 12158 4169 Copthorne Tara Hotel London Kensington 7105 3578 ... ... ... Mercure Paris Porte d Orleans 110 10 Hotel Wagner 135 10 Hotel Gallitzinberg 173 8 Je zult merken dat de geteld in de dataset-resultaten niet overeenkomen met de waarde in
Total_Number_of_Reviews
. Het is onduidelijk of deze waarde in de dataset het totale aantal recensies vertegenwoordigde dat het hotel had, maar niet allemaal werden gescraped, of een andere berekening.Total_Number_of_Reviews
wordt niet gebruikt in het model vanwege deze onduidelijkheid. -
Hoewel er een kolom
Average_Score
is voor elk hotel in de dataset, kun je ook een gemiddelde score berekenen (het gemiddelde van alle recensent-scores in de dataset voor elk hotel). Voeg een nieuwe kolom toe aan je dataframe met de kolomkopCalc_Average_Score
die dat berekende gemiddelde bevat. Print de kolommenHotel_Name
,Average_Score
enCalc_Average_Score
.# define a function that takes a row and performs some calculation with it def get_difference_review_avg(row): return row["Average_Score"] - row["Calc_Average_Score"] # 'mean' is mathematical word for 'average' df['Calc_Average_Score'] = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1) # Add a new column with the difference between the two average scores df["Average_Score_Difference"] = df.apply(get_difference_review_avg, axis = 1) # Create a df without all the duplicates of Hotel_Name (so only 1 row per hotel) review_scores_df = df.drop_duplicates(subset = ["Hotel_Name"]) # Sort the dataframe to find the lowest and highest average score difference review_scores_df = review_scores_df.sort_values(by=["Average_Score_Difference"]) display(review_scores_df[["Average_Score_Difference", "Average_Score", "Calc_Average_Score", "Hotel_Name"]])
Je vraagt je misschien af over de waarde
Average_Score
en waarom deze soms verschilt van de berekende gemiddelde score. Omdat we niet kunnen weten waarom sommige waarden overeenkomen, maar andere een verschil hebben, is het in dit geval het veiligst om de recensiescores die we hebben te gebruiken om het gemiddelde zelf te berekenen. Dat gezegd hebbende, zijn de verschillen meestal erg klein. Hier zijn de hotels met de grootste afwijking tussen het datasetgemiddelde en het berekende gemiddelde:Average_Score_Difference Average_Score Calc_Average_Score Hotel_Name -0.8 7.7 8.5 Best Western Hotel Astoria -0.7 8.8 9.5 Hotel Stendhal Place Vend me Paris MGallery -0.7 7.5 8.2 Mercure Paris Porte d Orleans -0.7 7.9 8.6 Renaissance Paris Vendome Hotel -0.5 7.0 7.5 Hotel Royal Elys es ... ... ... ... 0.7 7.5 6.8 Mercure Paris Op ra Faubourg Montmartre 0.8 7.1 6.3 Holiday Inn Paris Montparnasse Pasteur 0.9 6.8 5.9 Villa Eugenie 0.9 8.6 7.7 MARQUIS Faubourg St Honor Relais Ch teaux 1.3 7.2 5.9 Kube Hotel Ice Bar Met slechts 1 hotel met een scoreverschil groter dan 1, betekent dit dat we het verschil waarschijnlijk kunnen negeren en de berekende gemiddelde score kunnen gebruiken.
-
Bereken en print hoeveel rijen de waarde "No Negative" hebben in de kolom
Negative_Review
. -
Bereken en print hoeveel rijen de waarde "No Positive" hebben in de kolom
Positive_Review
. -
Bereken en print hoeveel rijen de waarde "No Positive" hebben in de kolom
Positive_Review
en de waarde "No Negative" in de kolomNegative_Review
.# with lambdas: start = time.time() no_negative_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" else False , axis=1) print("Number of No Negative reviews: " + str(len(no_negative_reviews[no_negative_reviews == True].index))) no_positive_reviews = df.apply(lambda x: True if x['Positive_Review'] == "No Positive" else False , axis=1) print("Number of No Positive reviews: " + str(len(no_positive_reviews[no_positive_reviews == True].index))) both_no_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" and x['Positive_Review'] == "No Positive" else False , axis=1) print("Number of both No Negative and No Positive reviews: " + str(len(both_no_reviews[both_no_reviews == True].index))) end = time.time() print("Lambdas took " + str(round(end - start, 2)) + " seconds") Number of No Negative reviews: 127890 Number of No Positive reviews: 35946 Number of both No Negative and No Positive reviews: 127 Lambdas took 9.64 seconds
Een andere manier
Een andere manier om items te tellen zonder Lambdas, en gebruik sum om de rijen te tellen:
# without lambdas (using a mixture of notations to show you can use both)
start = time.time()
no_negative_reviews = sum(df.Negative_Review == "No Negative")
print("Number of No Negative reviews: " + str(no_negative_reviews))
no_positive_reviews = sum(df["Positive_Review"] == "No Positive")
print("Number of No Positive reviews: " + str(no_positive_reviews))
both_no_reviews = sum((df.Negative_Review == "No Negative") & (df.Positive_Review == "No Positive"))
print("Number of both No Negative and No Positive reviews: " + str(both_no_reviews))
end = time.time()
print("Sum took " + str(round(end - start, 2)) + " seconds")
Number of No Negative reviews: 127890
Number of No Positive reviews: 35946
Number of both No Negative and No Positive reviews: 127
Sum took 0.19 seconds
Je hebt misschien gemerkt dat er 127 rijen zijn die zowel "No Negative" als "No Positive" waarden hebben voor de kolommen Negative_Review
en Positive_Review
respectievelijk. Dat betekent dat de recensent het hotel een numerieke score heeft gegeven, maar ervoor heeft gekozen om geen positieve of negatieve recensie te schrijven. Gelukkig is dit een klein aantal rijen (127 van 515738, of 0,02%), dus het zal waarschijnlijk ons model of de resultaten niet in een bepaalde richting beïnvloeden, maar je had misschien niet verwacht dat een dataset met recensies rijen zou bevatten zonder recensies, dus het is de moeite waard om de data te verkennen om dergelijke rijen te ontdekken.
Nu je de dataset hebt verkend, ga je in de volgende les de data filteren en sentimentanalyse toevoegen.
🚀Uitdaging
Deze les laat zien, zoals we in eerdere lessen zagen, hoe cruciaal het is om je data en de eigenaardigheden ervan te begrijpen voordat je bewerkingen uitvoert. Tekstgebaseerde data, in het bijzonder, vereist zorgvuldig onderzoek. Graaf door verschillende tekstrijke datasets en kijk of je gebieden kunt ontdekken die vooringenomenheid of scheve sentimenten in een model kunnen introduceren.
Post-lecture quiz
Review & Zelfstudie
Volg dit leerpad over NLP om tools te ontdekken die je kunt proberen bij het bouwen van spraak- en tekstrijke modellen.
Opdracht
Disclaimer:
Dit document is vertaald met behulp van de AI-vertalingsservice Co-op Translator. Hoewel we streven naar nauwkeurigheid, dient u zich ervan bewust te zijn dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in zijn oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor cruciale informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.