|
3 weeks ago | |
---|---|---|
.. | ||
solution | 3 weeks ago | |
README.md | 3 weeks ago | |
assignment.md | 3 weeks ago | |
notebook.ipynb | 3 weeks ago |
README.md
Análise de sentimento com avaliações de hotéis
Agora que você explorou o conjunto de dados em detalhes, é hora de filtrar as colunas e usar técnicas de NLP no conjunto de dados para obter novos insights sobre os hotéis.
Quiz pré-aula
Operações de filtragem e análise de sentimento
Como você provavelmente percebeu, o conjunto de dados tem alguns problemas. Algumas colunas estão preenchidas com informações inúteis, outras parecem incorretas. Mesmo que estejam corretas, não está claro como foram calculadas, e as respostas não podem ser verificadas de forma independente por seus próprios cálculos.
Exercício: um pouco mais de processamento de dados
Limpe os dados um pouco mais. Adicione colunas que serão úteis mais tarde, altere os valores em outras colunas e elimine algumas colunas completamente.
-
Processamento inicial de colunas
-
Elimine
lat
elng
-
Substitua os valores de
Hotel_Address
pelos seguintes valores (se o endereço contiver o nome da cidade e do país, altere para apenas a cidade e o país).Estas são as únicas cidades e países no conjunto de dados:
Amsterdam, Netherlands
Barcelona, Spain
London, United Kingdom
Milan, Italy
Paris, France
Vienna, Austria
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" # Replace all the addresses with a shortened, more useful form df["Hotel_Address"] = df.apply(replace_address, axis = 1) # The sum of the value_counts() should add up to the total number of reviews print(df["Hotel_Address"].value_counts())
Agora você pode consultar dados a nível de país:
display(df.groupby("Hotel_Address").agg({"Hotel_Name": "nunique"}))
Hotel_Address Hotel_Name Amsterdam, Netherlands 105 Barcelona, Spain 211 London, United Kingdom 400 Milan, Italy 162 Paris, France 458 Vienna, Austria 158
-
-
Processar colunas de meta-avaliação dos hotéis
-
Elimine
Additional_Number_of_Scoring
-
Substitua
Total_Number_of_Reviews
pelo número total de avaliações para aquele hotel que realmente estão no conjunto de dados -
Substitua
Average_Score
pela nossa própria pontuação calculada
# Drop `Additional_Number_of_Scoring`
df.drop(["Additional_Number_of_Scoring"], axis = 1, inplace=True)
# Replace `Total_Number_of_Reviews` and `Average_Score` with our own calculated values
df.Total_Number_of_Reviews = df.groupby('Hotel_Name').transform('count')
df.Average_Score = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
-
Processar colunas de avaliação
-
Elimine
Review_Total_Negative_Word_Counts
,Review_Total_Positive_Word_Counts
,Review_Date
edays_since_review
-
Mantenha
Reviewer_Score
,Negative_Review
ePositive_Review
como estão -
Mantenha
Tags
por enquanto
- Faremos algumas operações adicionais de filtragem nas tags na próxima seção e, em seguida, as tags serão eliminadas
-
-
Processar colunas de avaliadores
-
Elimine
Total_Number_of_Reviews_Reviewer_Has_Given
-
Mantenha
Reviewer_Nationality
Colunas de tags
A coluna Tag
é problemática, pois é uma lista (em formato de texto) armazenada na coluna. Infelizmente, a ordem e o número de subseções nesta coluna nem sempre são os mesmos. É difícil para um humano identificar as frases corretas de interesse, porque há 515.000 linhas e 1427 hotéis, e cada um tem opções ligeiramente diferentes que um avaliador poderia escolher. É aqui que o NLP se destaca. Você pode escanear o texto e encontrar as frases mais comuns, e contá-las.
Infelizmente, não estamos interessados em palavras isoladas, mas em frases compostas (por exemplo, Viagem de negócios). Executar um algoritmo de distribuição de frequência de frases compostas em tantos dados (6762646 palavras) pode levar um tempo extraordinário, mas sem olhar para os dados, parece que isso é uma despesa necessária. É aqui que a análise exploratória de dados é útil, porque você viu uma amostra das tags como [' Business trip ', ' Solo traveler ', ' Single Room ', ' Stayed 5 nights ', ' Submitted from a mobile device ']
, você pode começar a perguntar se é possível reduzir significativamente o processamento necessário. Felizmente, é - mas primeiro você precisa seguir alguns passos para determinar as tags de interesse.
Filtrando tags
Lembre-se de que o objetivo do conjunto de dados é adicionar sentimento e colunas que ajudarão você a escolher o melhor hotel (para você ou talvez para um cliente que lhe pediu para criar um bot de recomendação de hotéis). Você precisa se perguntar se as tags são úteis ou não no conjunto de dados final. Aqui está uma interpretação (se você precisasse do conjunto de dados para outros motivos, tags diferentes poderiam permanecer/ser removidas da seleção):
- O tipo de viagem é relevante e deve permanecer
- O tipo de grupo de hóspedes é importante e deve permanecer
- O tipo de quarto, suíte ou estúdio em que o hóspede ficou é irrelevante (todos os hotéis têm basicamente os mesmos quartos)
- O dispositivo no qual a avaliação foi enviada é irrelevante
- O número de noites que o avaliador ficou poderia ser relevante se você atribuísse estadias mais longas ao fato de eles gostarem mais do hotel, mas é algo incerto e provavelmente irrelevante
Em resumo, mantenha 2 tipos de tags e remova as outras.
Primeiro, você não quer contar as tags até que estejam em um formato melhor, o que significa remover os colchetes e aspas. Você pode fazer isso de várias maneiras, mas deve escolher a mais rápida, pois pode levar muito tempo para processar muitos dados. Felizmente, o pandas tem uma maneira fácil de realizar cada uma dessas etapas.
# Remove opening and closing brackets
df.Tags = df.Tags.str.strip("[']")
# remove all quotes too
df.Tags = df.Tags.str.replace(" ', '", ",", regex = False)
Cada tag se torna algo como: Business trip, Solo traveler, Single Room, Stayed 5 nights, Submitted from a mobile device
.
Em seguida, encontramos um problema. Algumas avaliações, ou linhas, têm 5 colunas, outras 3, outras 6. Isso é resultado de como o conjunto de dados foi criado e difícil de corrigir. Você quer obter uma contagem de frequência de cada frase, mas elas estão em ordens diferentes em cada avaliação, então a contagem pode estar errada, e um hotel pode não receber uma tag que merecia.
Em vez disso, você usará a ordem diferente a seu favor, porque cada tag é composta por várias palavras, mas também separada por uma vírgula! A maneira mais simples de fazer isso é criar 6 colunas temporárias com cada tag inserida na coluna correspondente à sua ordem na tag. Você pode então mesclar as 6 colunas em uma grande coluna e executar o método value_counts()
na coluna resultante. Ao imprimir isso, você verá que havia 2428 tags únicas. Aqui está uma pequena amostra:
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 |
Algumas das tags comuns, como Submitted from a mobile device
, não são úteis para nós, então pode ser inteligente removê-las antes de contar a ocorrência de frases, mas é uma operação tão rápida que você pode deixá-las e ignorá-las.
Removendo tags de duração da estadia
Remover essas tags é o primeiro passo, reduzindo ligeiramente o número total de tags a serem consideradas. Note que você não as remove do conjunto de dados, apenas escolhe removê-las da consideração como valores a serem contados/mantidos no conjunto de dados de avaliações.
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 |
... | ... |
Há uma enorme variedade de quartos, suítes, estúdios, apartamentos e assim por diante. Todos significam basicamente a mesma coisa e não são relevantes para você, então remova-os da consideração.
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 |
Finalmente, e isso é ótimo (porque não exigiu muito processamento), você ficará com as seguintes tags úteis:
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 |
Você poderia argumentar que Travellers with friends
é o mesmo que Group
mais ou menos, e seria justo combinar os dois como acima. O código para identificar as tags corretas está no notebook de Tags.
O passo final é criar novas colunas para cada uma dessas tags. Então, para cada linha de avaliação, se a coluna Tag
corresponder a uma das novas colunas, adicione 1, caso contrário, adicione 0. O resultado final será uma contagem de quantos avaliadores escolheram este hotel (em agregado) para, por exemplo, negócios vs lazer, ou para trazer um animal de estimação, e isso é informação útil ao recomendar um hotel.
# Process the Tags into new columns
# The file Hotel_Reviews_Tags.py, identifies the most important tags
# Leisure trip, Couple, Solo traveler, Business trip, Group combined with 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)
Salve seu arquivo
Finalmente, salve o conjunto de dados como está agora com um novo nome.
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)
# Saving new data file with calculated columns
print("Saving results to Hotel_Reviews_Filtered.csv")
df.to_csv(r'../data/Hotel_Reviews_Filtered.csv', index = False)
Operações de análise de sentimento
Nesta seção final, você aplicará análise de sentimento às colunas de avaliação e salvará os resultados em um conjunto de dados.
Exercício: carregar e salvar os dados filtrados
Note que agora você está carregando o conjunto de dados filtrado que foi salvo na seção anterior, não o conjunto de dados original.
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')
# Load the filtered hotel reviews from CSV
df = pd.read_csv('../../data/Hotel_Reviews_Filtered.csv')
# You code will be added here
# Finally remember to save the hotel reviews with new NLP data added
print("Saving results to Hotel_Reviews_NLP.csv")
df.to_csv(r'../data/Hotel_Reviews_NLP.csv', index = False)
Removendo stop words
Se você fosse executar a análise de sentimento nas colunas de avaliação negativa e positiva, isso poderia levar muito tempo. Testado em um laptop de teste poderoso com CPU rápida, levou de 12 a 14 minutos, dependendo de qual biblioteca de análise de sentimento foi usada. Esse é um tempo (relativamente) longo, então vale a pena investigar se isso pode ser acelerado.
Remover stop words, ou palavras comuns em inglês que não alteram o sentimento de uma frase, é o primeiro passo. Ao removê-las, a análise de sentimento deve ser mais rápida, mas não menos precisa (já que as stop words não afetam o sentimento, mas elas desaceleram a análise).
A avaliação negativa mais longa tinha 395 palavras, mas após remover as stop words, ficou com 195 palavras.
Remover as stop words também é uma operação rápida, removê-las de 2 colunas de avaliação em mais de 515.000 linhas levou 3,3 segundos no dispositivo de teste. Pode levar um pouco mais ou menos tempo para você, dependendo da velocidade da CPU do seu dispositivo, RAM, se você tem um SSD ou não, e outros fatores. A relativa rapidez da operação significa que, se ela melhorar o tempo de análise de sentimento, então vale a pena fazer.
from nltk.corpus import stopwords
# Load the hotel reviews from CSV
df = pd.read_csv("../../data/Hotel_Reviews_Filtered.csv")
# Remove stop words - can be slow for a lot of text!
# Ryan Han (ryanxjhan on Kaggle) has a great post measuring performance of different stop words removal approaches
# https://www.kaggle.com/ryanxjhan/fast-stop-words-removal # using the approach that Ryan recommends
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
# Remove the stop words from both columns
df.Negative_Review = df.Negative_Review.apply(remove_stopwords)
df.Positive_Review = df.Positive_Review.apply(remove_stopwords)
Realizando análise de sentimento
Agora você deve calcular a análise de sentimento para as colunas de avaliação negativa e positiva e armazenar o resultado em 2 novas colunas. O teste da análise de sentimento será compará-lo com a pontuação do avaliador para a mesma avaliação. Por exemplo, se a análise de sentimento indicar que a avaliação negativa teve um sentimento de 1 (sentimento extremamente positivo) e a avaliação positiva também teve um sentimento de 1, mas o avaliador deu ao hotel a menor pontuação possível, então ou o texto da avaliação não corresponde à pontuação, ou o analisador de sentimento não conseguiu reconhecer o sentimento corretamente. Você deve esperar que algumas pontuações de sentimento estejam completamente erradas, e muitas vezes isso será explicável, por exemplo, a avaliação pode ser extremamente sarcástica: "Claro que eu AMEI dormir em um quarto sem aquecimento", e o analisador de sentimento pode interpretar isso como um sentimento positivo, mesmo que um humano lendo saiba que foi sarcasmo. O NLTK oferece diferentes analisadores de sentimento para você experimentar, e é possível substituí-los para verificar se a análise de sentimento é mais ou menos precisa. Aqui, utilizamos a análise de sentimento VADER.
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, junho de 2014.
from nltk.sentiment.vader import SentimentIntensityAnalyzer
# Create the vader sentiment analyser (there are others in NLTK you can try too)
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.
# There are 3 possibilities of input for a review:
# It could be "No Negative", in which case, return 0
# It could be "No Positive", in which case, return 0
# It could be a review, in which case calculate the sentiment
def calc_sentiment(review):
if review == "No Negative" or review == "No Positive":
return 0
return vader_sentiment.polarity_scores(review)["compound"]
Mais tarde, no seu programa, quando estiver pronto para calcular o sentimento, você pode aplicá-lo a cada avaliação da seguinte forma:
# Add a negative sentiment and positive sentiment column
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")
Isso leva aproximadamente 120 segundos no meu computador, mas o tempo pode variar dependendo do computador. Se você quiser imprimir os resultados e verificar se o sentimento corresponde à avaliação:
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"]])
A última coisa a fazer com o arquivo antes de usá-lo no desafio é salvá-lo! Também é recomendável reorganizar todas as suas novas colunas para que sejam fáceis de trabalhar (para um humano, é uma mudança estética).
# Reorder the columns (This is cosmetic, but to make it easier to explore the data later)
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)
Você deve executar todo o código do notebook de análise (depois de executar o notebook de filtragem para gerar o arquivo Hotel_Reviews_Filtered.csv).
Para revisar, os passos são:
- O arquivo do conjunto de dados original Hotel_Reviews.csv é explorado na lição anterior com o notebook de exploração
- O arquivo Hotel_Reviews.csv é filtrado pelo notebook de filtragem, resultando no Hotel_Reviews_Filtered.csv
- O arquivo Hotel_Reviews_Filtered.csv é processado pelo notebook de análise de sentimento, resultando no Hotel_Reviews_NLP.csv
- Use o arquivo Hotel_Reviews_NLP.csv no Desafio de NLP abaixo
Conclusão
Quando você começou, tinha um conjunto de dados com colunas e informações, mas nem tudo podia ser verificado ou utilizado. Você explorou os dados, filtrou o que não era necessário, converteu tags em algo útil, calculou suas próprias médias, adicionou algumas colunas de sentimento e, com sorte, aprendeu coisas interessantes sobre o processamento de texto natural.
Questionário pós-aula
Desafio
Agora que você analisou o sentimento do seu conjunto de dados, veja se consegue usar as estratégias aprendidas neste curso (talvez clustering?) para identificar padrões relacionados ao sentimento.
Revisão e Autoestudo
Faça este módulo do Learn para aprender mais e usar ferramentas diferentes para explorar o sentimento em textos.
Tarefa
Experimente um conjunto de dados diferente
Aviso Legal:
Este documento foi traduzido utilizando o serviço de tradução por IA Co-op Translator. Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original em seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional feita por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações equivocadas decorrentes do uso desta tradução.