Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

使用R和tidytext对Trustpilot 的评论进行主题建模

$
0
0

在这篇和分析中,我们将主题建模应用于我目前的电信提供商丹麦Trustpilot对“3”(其他国家的“三个”)的评论。 我对他们的客户服务不满意,并认为这将是一个有趣的主题建模用例。 通过这种方法, 我们可以尝试找出客户体验的哪些方面出现在积极和消极的评论中 。

我使用 python脚本 从trustpilot.dk抓取了从2015年1月到2017年10月期间4000条关于“3”的客户评论“3”。

有关使用Julia Silge和David Robinson的tidytext包进行主题建模的更多详细信息,请查看 他们的书 。

需要的包 if(!require("pacman")) install.packages("pacman") pacman::p_load(tidyverse,tidytext,tm,topicmodels,magrittr, jtools,gridExtra,knitr,widyr,ggraph,igraph,kableExtra) if(!require("devtools")) install.packages("devtools") devtools::install_github("56north/happyorsad") library(happyorsad) 定制化ggplot主题

改善ggplot2中图形的外观非常简单。 为了保持一致性,我们将根据jtools包中的APA主题创建一个干净简单的主题,并修改一些功能。 背景颜色将设置为浅灰色调。 APA主题中省略了网格线。

my_theme <- function() { theme_apa(legend.pos = "none") + theme(panel.background = element_rect(fill = "gray96", colour = "gray96"), plot.background = element_rect(fill = "gray96", colour = "gray96"), plot.margin = margin(1, 1, 1, 1, "cm"), panel.border = element_blank(), # facet border strip.background = element_blank()) # facet title background } 加载和准备数据

我们的数据框有两列:一个名为Name的变量,包含评论者/作者的名字,它将作为一个变量来识别每个文档; 一个名为Review的变量,包含单个评论。

df <- read_csv2("https://raw.githubusercontent.com/PeerChristensen/trustpilot_reviews/master/3reviewsB.csv") df %<>% select(-X1) %>% filter(Name != "John M. Sebastian")

鉴于我们的评论是丹麦语,我们可以使用happyorsad包计算每个评论的情绪评分。 分数基于丹麦的情绪词汇和FinnrupNielsen的分数列表。 我们还将确保所有单词都是小写的,并删除一堆预定义的丹麦停用词和频繁的动词。

df %<>% mutate(Sentiment = map_int(df$Review,happyorsad,"da")) %>% mutate(Review = tolower(Review)) %>% mutate(Review = removeWords(Review, c("s", "3", "kan","f","fr","fik", stopwords("danish")))) 情感分数的分布

在下面的密度图中,我们看到情感分数如何分布,中位数为2.正如您可能知道的那样,我们正在处理一个相当平庸的提供者。 但是,我们仍然想知道为什么该公司的评分为10分满分里的6.7分。

我们可以非常粗略地将正面和负面评论放在不同的数据框架中,并对每个数据框架进行主题建模,以便探索哪些评论者喜欢和不喜欢3。

df %>% ggplot(aes(x = Sentiment)) + geom_density(size = 1) + geom_vline(xintercept = median(df$Sentiment), colour = "indianred", linetype = "dashed", size = 1) + ggplot2::annotate("text", x = 15, y = 0.06, label = paste("median = ", median(df$Sentiment)), colour = "indianred") + my_theme() + xlim(-40,40)
使用R和tidytext对Trustpilot 的评论进行主题建模
用于积极评论的主题建模

下面创建的数据框包含2228个正面评论,分数高于1.单词将被分词化,即每行一个单词。

df_pos <- df %>% filter(Sentiment > 1) %>% select(-Sentiment) %>% unnest_tokens(word, Review)

在创建所谓的文档术语矩阵之前,我们需要计算每个文档(评论)的每个单词的频率。

words_pos <- df_pos %>% count(Name, word, sort = TRUE) %>% ungroup() reviewDTM_pos <- words_pos %>% cast_dtm(Name, word, n)

现在我们有了一个“DTM”,我们可以将它传递给LDA函数,它实现了Latent Dirichlet Allocation算法。 它假定每个文档都是主题的混合,每个主题都是单词的混合。 k参数用于指定我们在模型中所需的主题数量。 让我们创建一个四主题模型!

reviewLDA_pos <- LDA(reviewDTM_pos, k = 4, control = list(seed = 347))

下图显示了分配给每个主题的评论数量。

tibble(topics(reviewLDA_pos)) %>% group_by(`topics(reviewLDA_pos)`) %>% count() %>% kable() %>% kable_styling(full_width = F, position = "left")
使用R和tidytext对Trustpilot 的评论进行主题建模

我们还可以得到每个主题每个单词的概率,或“beta”。

topics_pos <- tidy(reviewLDA_pos, matrix = "beta") topics_pos ## # A tibble: 46,844 x 3 ## topic term beta ## <int> <chr> <dbl> ## 1 1 telefon 0.00376 ## 2 2 telefon 0.00358 ## 3 3 telefon 0.0165 ## 4 4 telefon 0.00319 ## 5 1 abonnement 0.00326 ## 6 2 abonnement 0.00871 ## 7 3 abonnement 0.00193 ## 8 4 abonnement 0.0130 ## 9 1 navn 0.000964 ## 10 2 navn 0.0000227 ## # ... with 46,834 more rows

现在,我们可以找到每个主题的Top术语,即具有最高概率/ beta的单词。 在这里,我们选择前五个单词,我们将在一个图片中显示。

topTerms_pos <- topics_pos %>% group_by(topic) %>% top_n(5, beta) %>% ungroup() %>% arrange(topic, -beta) %>% mutate(order = rev(row_number())) 针对负面评论的主题建模

让我们首先对负面评论做同样的事情,创建一个包含973条评论的数据框架,其情绪得分低于-1。

df_neg <- df %>% filter(Sentiment < -1) %>% select(-Sentiment) %>% unnest_tokens(word, Review) words_neg <- df_neg %>% count(Name, word, sort = TRUE) %>% ungroup() reviewDTM_neg <- words_neg %>% cast_dtm(Name, word, n) reviewLDA_neg <- LDA(reviewDTM_neg, k = 4, control = list(seed = 347)) tibble(topics(reviewLDA_neg)) %>% group_by(`topics(reviewLDA_neg)`) %>% count() %>% kable() %>% kable_styling(full_width = F, position = "left")
使用R和tidytext对Trustpilot 的评论进行主题建模
topics_neg <- tidy(reviewLDA_neg, matrix = "beta") topTerms_neg <- topics_neg %>% group_by(topic) %>% top_n(5, beta) %>% ungroup() %>% arrange(topic, -beta) %>% mutate(order = rev(row_number())) 绘制主题模型

最后,让我们画出结果。

plot_pos <- topTerms_pos %>% ggplot(aes(order, beta)) + ggtitle("Positive review topics") + geom_col(show.legend = FALSE, fill = "steelblue") + scale_x_continuous( breaks = topTerms_pos$order, labels = topTerms_pos$term, expand = c(0,0)) + facet_wrap(~ topic,scales = "free") + coord_flip(ylim = c(0,0.02)) + my_theme() + theme(axis.title = element_blank()) plot_neg <- topTerms_neg %>% ggplot(aes(order, beta, fill = factor(topic))) + ggtitle("Negative review topics") + geom_col(show.legend = FALSE, fill = "indianred") + scale_x_continuous( breaks = topTerms_neg$order, labels = topTerms_neg$term, expand = c(0,0))+ facet_wrap(~ topic,scales = "free") + coord_flip(ylim = c(0,0.02)) + my_theme() + theme(axis.title = element_blank()) grid.arrange(plot_pos, plot_neg, ncol = 1)
使用R和tidytext对Trustpilot 的评论进行主题建模

那么,客户在Trustpilot.dk上撰写评论喜欢和不喜欢什么? 不幸的是,这些评论都是丹麦语,但考虑到积极和消极评论的四个主题模型,这里是人们倾向于强调的内容:

积极评价:

覆盖面和数据 服务 手机,商店和新商店――也许商店经常更换出故障的手机? 计划(服务),丹麦克朗(丹麦货币),支付,账单-计划和支付的积极方面?

消极评价:

客户服务,计划 客户服务,电话,错误,计划 电话,覆盖率,商店 支付,账单,kr,计划

有趣的是,对于几乎相同的主题,客户似乎既有积极的体验,也有消极的体验。一些客户似乎体验到了良好的覆盖率,而另一些客户似乎抱怨覆盖率低。(客户)服务和支付也出现了相同的模式。

让我们进一步探索。

评论中的单词共现

为了查看在我们的两个数据集中是否经常使用“良好服务”和“不良服务”这样的单词对,我们将计算每对单词在标题或描述字段中出现的次数。 使用widyr包中的pairwise_count()很容易。

word_pairs_pos <- df_pos %>% pairwise_count(word, Name, sort = TRUE) word_pairs_neg <- df_neg %>% pairwise_count(word, Name, sort = TRUE)

然后,我们可以使用igraph和ggraph包绘制评论中同时出现的最常见的单词对。

set.seed(611) pairs_plot_pos <- word_pairs_pos %>% filter(n >= 140) %>% graph_from_data_frame() %>% ggraph(layout = "fr") + g

Viewing all articles
Browse latest Browse all 12749

Latest Images

Trending Articles





Latest Images