|
| 1 | +原文:[Machine Learning over 1M hotel reviews finds interesting insights](https://blog.monkeylearn.com/machine-learning-1m-hotel-reviews-finds-interesting-insights/) |
| 2 | + |
| 3 | +--- |
| 4 | + |
| 5 | +在[之前的文章](https://blog.monkeylearn.com/creating-aspect-classifier-from-reviews-using-machine-learning/)中,我们学会了如何训练一个机器学习分类器,用来检测酒店点评中提到的不同方面。使用这个[方面分类器](https://app.monkeylearn.com/main/classifiers/cl_TKb7XmdG/),我们可以自动的知道一个特定的点评是否在谈论清洁、舒适和设施、食品、网络、地点、工作人员以及/或物有所值。 |
| 6 | + |
| 7 | +我们还学习了如何将这个分类器与[情绪分析分类器](https://blog.monkeylearn.com/creating-sentiment-analysis-model-with-scrapy-and-monkeylearn/)结合在一起,获得有趣的见解以及回答诸如客人喜欢特定酒店的位置,但是抱怨它的清洁问题吗这样的问题。 |
| 8 | + |
| 9 | +在这篇文章中,我们将介绍我们可以如何使用这些机器学习模型来分析TripAdvisor上数百万条点评,然后比较人们对不同城市的酒店的感受,从而理解以下事情: |
| 10 | + |
| 11 | + * 待在曼谷酒店的人会比那些待在,比方说,巴黎酒店的人更多抱怨清洁问题吗? |
| 12 | + * 具有最糟糕设施的城市是哪个? |
| 13 | + * [酒店的星](https://en.wikipedia.org/wiki/Hotel_rating)数会影响它的评论吗? |
| 14 | + * 当涉及到不同类别的酒店时,人们会有不同的标准吗? |
| 15 | + |
| 16 | +这是我们这篇教程想要回答的问题,而这将带给我们一些有趣的见解。这个过程的源代码可以在这个[repo](https://github.com/monkeylearn/hotel-review-analysis)找到。 |
| 17 | + |
| 18 | +## 爬取酒店点评 |
| 19 | + |
| 20 | +我们创建了在[前一篇文章](https://blog.monkeylearn.com/creating-sentiment-analysis-model-with-scrapy-and-monkeylearn/)构建的[TripAdvisor Spider](https://github.com/monkeylearn/hotel-review-analysis)的一个新版本,用它来收集点评的更多数据: |
| 21 | + |
| 22 | + * 酒店的名字。 |
| 23 | + * 酒店所在的城市。 |
| 24 | + * 酒店的星级(由点评者提供)。 |
| 25 | + |
| 26 | +## 创建一个Pipeline来合并模型 |
| 27 | + |
| 28 | +在使用新的爬虫从TripAdvisor抓取了一百多万条点评后,我们将内容拆分成意见单元,并且使用[之前](https://blog.monkeylearn.com/creating-aspect-classifier-from-reviews-using-machine-learning/)做过的类似的方式来将其分类。最大的区别是,现在我们创建了一个[pipeline](http://docs.monkeylearn.com/article/what-are-pipelines/),它将两个分类器结合起来。pipeline是一个非常强大且灵活的工具,它允许你将MonkeyLearn的不同模块组合起来,多亏了它们,一次请求就可以同时为方面和情绪进行分类。 |
| 29 | + |
| 30 | +下面是使用pipeline分类意见单元: |
| 31 | + |
| 32 | +```Python |
| 33 | +from monkeylearn import MonkeyLearn |
| 34 | +ml = MonkeyLearn("<your api key here>") |
| 35 | +data = { |
| 36 | + "texts": [{"text": "The room was very clean"}, {"text": "very rude staff"}] |
| 37 | +} |
| 38 | +res = ml.pipelines.run('pi_YKStimMw', data, sandbox=False) |
| 39 | +``` |
| 40 | + |
| 41 | +简单吧?然后,res.result是一个看起来像这样的JSON: |
| 42 | + |
| 43 | +```javascript |
| 44 | +{ |
| 45 | + 'tags': [{ |
| 46 | + 'sentiment': [{ |
| 47 | + 'category_id': 102881, |
| 48 | + 'label': 'Good', |
| 49 | + 'probability': 1.0 |
| 50 | + }], |
| 51 | + 'topic': [ |
| 52 | + [{ |
| 53 | + 'category_id': 1495678, |
| 54 | + 'label': 'Cleanliness', |
| 55 | + 'probability': 1.0 |
| 56 | + }] |
| 57 | + ] |
| 58 | + }, { |
| 59 | + 'sentiment': [{ |
| 60 | + 'category_id': 102882, |
| 61 | + 'label': 'Bad', |
| 62 | + 'probability': 1.0 |
| 63 | + }], |
| 64 | + 'topic': [ |
| 65 | + [{ |
| 66 | + 'category_id': 1495676, |
| 67 | + 'label': 'Staff', |
| 68 | + 'probability': 1.0 |
| 69 | + }] |
| 70 | + ] |
| 71 | + }] |
| 72 | +} |
| 73 | + |
| 74 | +``` |
| 75 | + |
| 76 | +每个点评都有一个item发送到pipeline,而每一个都有情绪和主题列表(方面)。 |
| 77 | + |
| 78 | +当将这些结果保存到CSV文件的时候,我们还添加了一个到其父评论的连接,并带有从点评文本的哈希值生成的键。因此,现在,我们有两个文件:一个是点评,包含我们爬取的每个点评的元数据(城市、酒店位置、星级等等),另一个是分类的意见单元,情绪和每个单元的主题,情绪可能性以及到其父点评的一个链接。 |
| 79 | + |
| 80 | +## 使用Elasticsearch对结果建索引 + Kibana可视化 |
| 81 | + |
| 82 | +但我们并不就此止步。接着,我们用[Elasticsearch](https://www.elastic.co/products/elasticsearch)来对结果建立索引,然后将它们加载到[Kibana](https://www.elastic.co/products/kibana),以生成漂亮的可视化。 |
| 83 | + |
| 84 | +这非常简单。首先,我们安装Elasticsearch,然后让它作为本地实例运行。为了获得数据的最好模型,需要进行一些试错,我们使用[sense](https://chrome.google.com/webstore/detail/sense-beta/lhjgkmllcaadmopgmanpapmpjgmfcfig?hl=en)来做这件事。它是一个不错的Chrome扩展,允许你使用一个漂亮的界面而不是使用cURL与elastic的API进行交互。我们创建两个类型的索引:_review_和_opinion_unit_。每个类型的字段是csv的字段,并且使用__parent_属性,我们添加来自每个意见单元的链接到它的父点评。最后,使用[python SDK](https://www.elastic.co/guide/en/elasticsearch/client/python-api/current/index.html)对csv文件的数据进行索引。 |
| 85 | + |
| 86 | +使用该SDK对意见单元进行索引是非常简单的。你只需要创建一个带有该item的所有字段的Python字典,然后使用该SDK发送到elasticsearch。批量进行比一次发送一个更快: |
| 87 | + |
| 88 | +```python |
| 89 | +es = Elasticsearch(['http://localhost:9200']) |
| 90 | +actions = [] |
| 91 | + |
| 92 | +parent_key = 'bd1ed398a8529d5ad010d927d5af7240' |
| 93 | +opinion_unit = "The room was very clean" |
| 94 | +sentiment = "Good" |
| 95 | +topic = "Cleanliness" |
| 96 | +item = [parent_key, opinion_unit, sentiment, topic] |
| 97 | +action = { |
| 98 | + "_index": "index_hotels", |
| 99 | + "_type": "opinion_unit", |
| 100 | + "_id": cont_id, |
| 101 | + "_parent": parent_key, |
| 102 | + "_source": item |
| 103 | + } |
| 104 | +actions.append(action) |
| 105 | + |
| 106 | +helpers.bulk(es, actions) |
| 107 | +``` |
| 108 | + |
| 109 | +随后,安装Kibana,然后将其配置为指向我们的Elasticsearch本地实例。为了创建在下面的部分展示的图表,我们使用基于查询的JSON,而不是Lucene,因为我们需要使用_has_parent_和_has_child_。 |
| 110 | + |
| 111 | +下面是一个查询,它从纽约选择意见单元。它使用带有_has_parent_的过滤器,这意味着它将只匹配父元素(一条点评)满足需求(来自纽约)的元素(意见单元)。它还要求意见单元的情绪根据高于某个特定的阈值的可能性进行分类,这将提高结果的质量: |
| 112 | + |
| 113 | +```javascript |
| 114 | +{ |
| 115 | + "query": { |
| 116 | + "filtered": { |
| 117 | + "query": { |
| 118 | + "match_all": { |
| 119 | + "range": { |
| 120 | + "sent_probability": { |
| 121 | + "gt": "0.501" |
| 122 | + } |
| 123 | + } |
| 124 | + } |
| 125 | + }, |
| 126 | + "filter": { |
| 127 | + "has_parent": { |
| 128 | + "type": "review", |
| 129 | + "query": { |
| 130 | + "match": { |
| 131 | + "city": "New York City" |
| 132 | + } |
| 133 | + } |
| 134 | + } |
| 135 | + } |
| 136 | + } |
| 137 | + } |
| 138 | +} |
| 139 | +``` |
| 140 | + |
| 141 | +用于创建图表的大多数查询都跟这个类似,你可以在[Github](https://github.com/monkeylearn/hotel-review-analysis/tree/master/classify_elastic/queries)找到它们。 |
| 142 | + |
| 143 | +## 来自点评的一些见解 |
| 144 | + |
| 145 | +### 大部分点评是正面的 |
| 146 | + |
| 147 | +纵观全局,大多数的点评是正面的。对于所有分析的意见单元,82%拥有一个“正面的”情绪。这意味着,人们在酒店点评中写的平均82%的东西都是正面的: |
| 148 | + |
| 149 | + |
| 150 | + |
| 151 | +全部4,000,000个意见单元的情绪 |
| 152 | + |
| 153 | +### 伦敦的酒店有最糟糕的点评 |
| 154 | + |
| 155 | +然而,一旦你按照城市对点评的情绪进行分段,事情就开始变得有趣起来:伦敦的酒店倾向于比其他城市更严厉。我们对这一结果感到惊讶,因为我们期望的是伦敦与纽约或者巴黎处在相同的水平。随着每年都有数百万的游客来到这个城市,值得注意的是,它与其他同样大小的城市得分不同: |
| 156 | + |
| 157 | + |
| 158 | + |
| 159 | +跨越不同城市的酒店点评的情绪 |
| 160 | + |
| 161 | +这个模型并未对这个行为进行解释,它只提供了结果。难道这是著名的糟糕的英国客户服务的征兆?或者也许伦敦的酒店只是比其他城市糟糕?又或者这是因为人们对伦敦的酒店更加苛刻?(请在下面的评论中分享你对这个结果的观点) |
| 162 | + |
| 163 | +### 伦敦比纽约脏,并且总体具有最糟糕的食物 |
| 164 | + |
| 165 | +另一个有趣的见解来自于对跨不同哦城市酒店的具体方面的整体情绪的比较。 |
| 166 | + |
| 167 | +作为城市的整体情绪,某些方面保持大致相同的水平:伦敦酒店的“舒适度(Comfort)和设施(Facilities)”比纽约的低,等等。 |
| 168 | + |
| 169 | +好玩的是,不是所有的方面都遵循这个模式。例如,对于所有城市来说,“位置(Location)”往往是非常积极的,这意味着当点评者提到酒店位置时,它通常因为他们喜欢它,并且很少抱怨。“食物(Food)”的情况相同,除了伦敦还是明显低于其他城市外。这可能是因为英国菜名声不好: |
| 170 | + |
| 171 | + |
| 172 | + |
| 173 | +跨不同城市的不同方面的情绪 |
| 174 | + |
| 175 | +### 具有不同星级的酒店的情绪 |
| 176 | + |
| 177 | +我们做了最后的比较,以找出人们对于不同星级的酒店有怎样的感受哦。似乎游客保持相同的标准而不管他们住在哪个酒店,因为点评的正面性随着星级的上升而上升: |
| 178 | + |
| 179 | + |
| 180 | + |
| 181 | +不同星级的酒店的整体情绪 |
| 182 | + |
| 183 | +### 网络一直是一个问题 |
| 184 | + |
| 185 | +有趣的是,“网络(Internet)”在任何星级的酒店都没有真正上升到70%以上,这表明3星级的酒店跟5星级的酒店的网络状态一样糟糕。人们会期望越昂贵的酒店会提供更好的网络服务,但如果你曾经住过一家五星级酒店,那么你会知道并不是这样的: |
| 186 | + |
| 187 | + |
| 188 | + |
| 189 | +不同星级的酒店的网络情绪 |
| 190 | + |
| 191 | +### 3星级的酒店最物有所值 |
| 192 | + |
| 193 | +另一个点评不一样的酒店方面是“物有所值(Value for Money)”,这个在3星级达到顶峰,随后下降。这表明,那些3星级,甚至2星级的酒店更加物有所值,即使它们比更高星级的酒店拥有更多的负面评价: |
| 194 | + |
| 195 | + |
| 196 | + |
| 197 | +不同星级酒店的价值 |
| 198 | + |
| 199 | +## 关键字提取的上下文分析 |
| 200 | + |
| 201 | +数字没问题,那么实际_内容_呢?对于清洁的点评,哪个城市获得称赞?每个酒店对于食物的共同抱怨是啥?为了找出这些答案,我们使用[关键词提取模块](https://app.monkeylearn.com/main/extractors/ex_y7BPYzNG/)。这是一个公共模块,给定一个文本,它会提取关键词,并按相关性排序。 |
| 202 | + |
| 203 | +为了从每个段获得关键词代表,我们将相同城市、方面和情绪的几百个意见单位合并成一个单一的文本,并从那个文本中提取关键词。下面是如何运行关键词提取器: |
| 204 | + |
| 205 | +```python |
| 206 | +ml = MonkeyLearn("<your api key here>") |
| 207 | +text = ["The carpets are a disgrace in the dining room and need replaced immediately. The room was frankly grim....old, saggy beds (all 3 of them), scuffed walls and decor, the hotel is SO old, smells old, and TINY!"] |
| 208 | +module_id = 'ex_y7BPYzNG' |
| 209 | +res = ml.extractors.extract(module_id, text) |
| 210 | +``` |
| 211 | + |
| 212 | +结果是一个JSON,它包含提取的关键词和关于它们的信息,例如相关性和出现次数。 |
| 213 | + |
| 214 | +例如,这些是纽约酒店点评中带有'Cleanliness'方面的'Bad'情绪的前10个关键词及其由MonkeyLearn返回的相关性: |
| 215 | + |
| 216 | +```python |
| 217 | +for d in res.result[0]: |
| 218 | + print d["keyword"], d["relevance"] |
| 219 | + |
| 220 | +room 0.999 |
| 221 | +bathroom 0.790 |
| 222 | +carpet 0.407 |
| 223 | +towels 0.311 |
| 224 | +bed bugs 0.246 |
| 225 | +bed 0.232 |
| 226 | +hotel 0.196 |
| 227 | +shower 0.155 |
| 228 | +shared bathroom 0.150 |
| 229 | +walls 0.138 |
| 230 | +``` |
| 231 | + |
| 232 | +在为每个段完成提取后,我们比较了从每个城市获取的关键词:哪一个是唯一的,哪一个地多个地点共有的。 |
| 233 | + |
| 234 | +### 曼谷有蟑螂问题 |
| 235 | + |
| 236 | +这个分析给了我们关于每个城市中的酒店之间的差异和相似之处的一些非常有趣的见解。 |
| 237 | + |
| 238 | +例如,对于每个城市来说,清洁投诉常见的是低碳、床、头发、臭虫、污渍这些东西。然而,蟑螂只出现在曼谷,这意味着,曼谷酒店的蟑螂状况比其他地方严重得多。 |
| 239 | + |
| 240 | +公共澡堂只出现在纽约,这可能意味着在纽约,公共澡堂更常见,并且它们脏得很! |
| 241 | + |
| 242 | +关于位置的意见的内容城市之间大不相同。不同地标名称的关键字在每个城市出现:在里约热内卢,评论提到诸如科帕卡巴纳,伊帕内马这样的东东;在北京,则是故宫和天安门广场之类;在马德里则是太阳门,等等等等。这些都是每个城市重要的旅游景点,因此当涉及到酒店的位置多好时,点评者认为它们是重要的。还有提到其他一些不是路标的城市特色,例如伦敦的地铁站,巴黎的地铁。 |
| 243 | + |
| 244 | +### 牛角包超让人失望 |
| 245 | + |
| 246 | +隐藏在此数据集后还有更多的见解,我们想要再提一个。也就是说,在不同城市关于食物的意见。早餐(breakfast)当然是一个共同的关键词,咖啡(coffee)和茶(tea)也是。然而,当我们考虑到单个城市的关键字时,事情变得有趣起来。 |
| 247 | + |
| 248 | +例如,关键词牛角包(croissant)只出现在来自巴黎的点评。另外,它大部分出现在一个负面的上下文中,这让人感到惊讶。为什么这样一种法国主食会出现在负面的角度呢?看看这些点评的内容,答案很清楚:牛角包在非常基础的早餐的情况下被提及。所以如果你去巴黎,平淡的早餐当然会包含一些牛角包(但没有别的了!) |
| 249 | + |
| 250 | +## 最后的话 |
| 251 | + |
| 252 | +在这篇教程中,我们学习了如何抓取上百万条点评,使用MonkeyLearn中的预训练分类器对他们进行分析,使用Elasticsearch对结果进行索引,并且使用Kibana进行可视化。 |
| 253 | + |
| 254 | +当你想要以低成本高效益的方式来分析大数据量时,机器学习就有意义了。 |
| 255 | + |
| 256 | +我们发现了一些真的很有趣的见解;一些如我们所料(像网络一直是一个问题),而一些完全出乎意料(伦敦酒店看起来最糟糕)。 |
| 257 | + |
| 258 | +如果你有机会,看看[代码](https://github.com/monkeylearn/hotel-review-analysis),并且进行你自己的分析,你将会发现玩数据和机器学习超级有意思。要是你这么做了,请在下面的评论,分享你的观点和结果,能够听到你的见解将是一件棒棒哒的事。 |
| 259 | + |
| 260 | +编码快乐! |
0 commit comments