├── .gitattributes
├── README.md
├── __pycache__
└── mysqls.cpython-36.pyc
├── 大众点评爬虫
├── CRAW_IP.py
├── README.md
├── main.py
├── mysqls.py
├── proxies.txt
└── xuchuan.txt
└── 文本分析挖掘
├── .ipynb_checkpoints
├── Untitled-checkpoint.ipynb
├── Untitled1-checkpoint.ipynb
├── 探索性数据分析-checkpoint.ipynb
└── 文本挖掘&情感分析-checkpoint.ipynb
├── data.csv
├── msyh.ttc
├── source
├── data_head.png
├── dianpu.png
├── len.png
├── stars.png
├── time.png
└── wordcloud.png
├── stopwords.txt
├── 探索性数据分析.ipynb
└── 文本挖掘&情感分析.ipynb
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 大众点评评论文本挖掘
2 |
3 | [TOC]
4 |
5 | ## 一、爬虫
6 |
7 | ### 整体思路
8 |
9 | 爬取大众点评十大热门糖水店的评论,爬取网页后从html页面中把需要的字段信息(顾客id、评论时间、评分、评论内容、口味、环境、服务、店铺ID)提取出来并存储到MYSQL数据库中。
10 |
11 | ### 网页爬取和解析
12 |
13 | 链接格式为"http://www.dianping.com/shop/" + shopID + "/review_all/" + pi,如:http://www.dianping.com/shop/518986/review_all/p1 ,一页评论有20条。我们使用for循环构造链接URL,使用requests库发起请求并把html页面爬取下来,通过BeautifulSoup和re库解析页面提取信息。
14 |
15 | 我们发现完整的评论都存储在'div','main-review'中,且部分页面口味、环境、服务并不是每一页都有,因此需要使用try...except...防止程序中断,BeautifulSoup部分代码如下:
16 |
17 | ``` python
18 | for item in soup('div','main-review'):
19 | cus_id = item.find('a','name').text.strip()
20 | comment_time = item.find('span','time').text.strip()
21 | comment_star = item.find('span',re.compile('sml-rank-stars')).get('class')[1]
22 | cus_comment = item.find('div',"review-words").text.strip()
23 | scores = str(item.find('span','score'))
24 | try:
25 | kouwei = re.findall(r'口味:([\u4e00-\u9fa5]*)',scores)[0]
26 | huanjing = re.findall(r'环境:([\u4e00-\u9fa5]*)',scores)[0]
27 | fuwu = re.findall(r'服务:([\u4e00-\u9fa5]*)',scores)[0]
28 | except:
29 | kouwei = huanjing = fuwu = '无'
30 | ```
31 |
32 | ### 数据存储
33 |
34 | 我们使用MYSQL数据库,安装教程参考[菜鸟教程](http://www.runoob.com/mysql/mysql-install.html),python连接MYSQL数据推荐使用pymysql,同样是推荐菜鸟教程[菜鸟教程](http://www.runoob.com/python3/python3-mysql.html)。我们需要先建立一个数据库和表,然后连接并定义游标,然后写对应的sql语句,最后执行事务,存储部分的代码如下:
35 |
36 | ``` python
37 | #连接MYSQL数据库
38 | db = pymysql.connect("localhost","root","","TESTDB" )
39 | cursor = db.cursor()
40 | #存储爬取到的数据
41 | def save_data(data_dict):
42 | sql = '''INSERT INTO DZDP(cus_id, comment_time, comment_star, cus_comment, kouwei, huanjing, fuwu, shopID) VALUES(%s,%s,%s,%s,%s,%s,%s,%s)'''
43 | value_tup = (data_dict['cus_id']
44 | ,data_dict['comment_time']
45 | ,data_dict['comment_star']
46 | ,data_dict['cus_comment']
47 | ,data_dict['kouwei']
48 | ,data_dict['huanjing']
49 | ,data_dict['fuwu']
50 | ,data_dict['shopID']
51 | )
52 | try:
53 | cursor.execute(sql,value_tup)
54 | db.commit()
55 | except:
56 | print('数据库写入失败')
57 | return
58 | ```
59 |
60 | ### 反爬虫对抗
61 |
62 | 1. **修改请求头中浏览器信息**:使用fake_useragent第三方库,修改request中的headers参数,用法如下:
63 |
64 | ``` python
65 | from fake_useragent import UserAgent
66 | ua = UserAgent()
67 | headers = {'User-Agent':ua.random}
68 | ```
69 |
70 | 2. **设置跳转路径**:在访问评论时,一般的浏览行为是从某一页跳转到下一页这样的,而不是直接通过连接访问,为了更好的伪装成一个正常的访问,我们需要设置一下跳转的路径,修改headers中的Referer参数
71 |
72 | ``` python
73 | headers = {
74 | 'User-Agent':ua.random,
75 | 'Cookie':cookie,
76 | 'Referer': 'http://www.dianping.com/shop/518986/review_all'
77 | }
78 | ```
79 |
80 | 3. **设置Cookies**:评论数据需要登录后才能获取,下面介绍一种非常简单方便的绕过登录的方法。
81 |
82 | - 在网页上进行登录
83 | - 使用Chrome浏览器的开发者工具,查询当前请求的cookie
84 | - 复制浏览器中的cookie,使用此cookie对我们的请求进行伪装
85 |
86 | 4. **使用IP代理池**:这里使用西刺代理的免费代理,构建一个爬虫爬取西刺代理的ip,然后进行验证,筛掉不可用的ip,构建出ip池供后续调用,代码来自网络。但是经过测试,大众点评对一个账号不同ip访问监控非常严格,使用IP代理池不更换账号的话,死的更快,封你账号,然而构建账号池比较麻烦,我们先暂缓。
87 |
88 | 5. **降低爬取频率**:一个简单又有效的方法就是降低爬取频率,毕竟高频率的爬取对服务器也是一个考验,如果对速度的要求不是很高的话,建议把频率放慢一点,你好我好大家好!
89 |
90 | ``` python
91 | import random
92 | import time
93 | time.sleep(6*random.random() + 4)
94 | ```
95 |
96 | 6. **设置断点续传**:即使降低了爬取频率,有时还是会被美团的网络工程师抓到的,小哥哥饶命啊~。因此我们需要一个断点续传的小功能,避免每次都从头开始爬。思路是建一个文本文件,存储当前爬取的进度,每次运行程序时都出当前进度开始,详见代码~
97 |
98 | ## 二、探索性分析与文本数据预处理
99 |
100 | ### 探索性分析
101 |
102 | 1. 查看数据大小以及基础信息 ,浏览数据
103 |
104 | 
105 |
106 | 2. 样本分布
107 |
108 | 
109 |
110 | 3. 各店铺评分分布
111 |
112 | 
113 |
114 | 4. 点评数的的时间分布
115 |
116 | 
117 |
118 | 5. 查看评论长度对结果影响
119 |
120 | 
121 | ### 数据预处理
122 |
123 | 1. **去除非文本数据**:可以看出,爬虫获取的数据非常多类似“\xa0”的非文本数据,而且都还有一些无意义的干扰数据,如结尾的“收起评论”
124 |
125 | ``` python
126 | #除去非文本数据和无意义文本
127 | data['cus_comment'] = data['cus_comment'].str.replace(r'[^\u4e00-\u9fa5]','').str.replace('收起评论','')
128 | ```
129 |
130 | 2. **中文分词**:中文文本数据处理,怎么能离开中文分词呢,我们使用jieba库,简单又好用。这里我们把文本字符串处理为以空格区隔的分词字符串
131 | ``` python
132 | #中文分词
133 | import jieba
134 | data['cus_comment'] = data['cus_comment'].apply(lambda x:' '.join(jieba.cut(x)))
135 | ```
136 |
137 | 3. **去除停用词**:文本中有很多无效的词,比如“着”,“和”,还有一些标点符号,这些我们不想在文本分析的时候引入,因此需要去掉,因为wordcloud和TF-IDF都支持停用词,因此就不额外处理了
138 |
139 | ### 词云展示
140 |
141 | 
142 |
143 | ## 三、文本的情感分析
144 |
145 | 先上结果:
146 |
147 | | 糖水店的评论文本 | 模型预测的情感评分 |
148 | | :------------------------------------------- | :----------------- |
149 | | '糖水味道不错,滑而不腻,赞一个,下次还会来' | 0.91 |
150 | | '味道一般,没啥特点' | 0.52 |
151 | | '排队老半天,环境很差,味道一般般' | 0.05 |
152 |
153 | 模型的效果还可以的样子,yeah~接下来我们好好讲讲怎么做的哈,我们通过爬虫爬取了大众点评广州8家最热门糖水店的3W条评论信息以及评分作为训练数据,前面的分析我们得知*样本很不均衡*。接下来我们的整体思路就是:文本特征提取(TF-IDF)—机器学习建模—模型评价。
154 |
155 | 我们先不处理样本不均衡问题,直接建模后查看结果,接下来我们再按照两种方法处理样本不均衡,对比结果。
156 |
157 | ### 文本特征提取(TF-IDF)
158 |
159 | 模型不能直接处理文本数据,因此需要先把文本数据转为向量,方法有词库表示法、TF-IDF、word2vec等,推荐一篇文章,总结得不错 https://zhuanlan.zhihu.com/p/44917421。
160 |
161 | ``` python
162 | #使用TF-IDF进行文本转向量处理
163 | from sklearn.feature_extraction.text import TfidfVectorizer
164 | tv = TfidfVectorizer(stop_words=stopwords, max_features=3000, ngram_range=(1,2))
165 | tv.fit(x_train)
166 | ```
167 |
168 | ### 机器学习建模
169 |
170 | 这里我们使用文本分类的经典算法朴素贝叶斯算法,而且朴素贝叶斯算法的计算量较少。特征值是评论文本经过TF-IDF处理的向量,标签值评论的分类共两类,好评是1,差评是0。情感评分为分类器预测分类1的概率值。
171 |
172 | ``` python
173 | #计算分类效果的准确率
174 | from sklearn.naive_bayes import MultinomialNB
175 | from sklearn.metrics import roc_auc_score, f1_score
176 | classifier = MultinomialNB()
177 | classifier.fit(tv.transform(x_train), y_train)
178 | classifier.score(tv.transform(x_test), y_test)
179 |
180 | >>>0.9275308869629356
181 | ```
182 |
183 | 可以看出,准确率非常不错的样子
184 |
185 | ``` python
186 | #从大众点评网找两条评论来测试一下
187 | test1 = '很好吃,环境好,所有员工的态度都很好,上菜快,服务也很好,味道好吃,都是用蒸馏水煮的,推荐,超好吃' #5星好评
188 | test2 = '糯米外皮不绵滑,豆沙馅粗躁,没有香甜味。12元一碗不值。' #1星差评
189 | print('好评实例的模型预测情感得分为{}\n差评实例的模型预测情感得分为{}'.format(ceshi(classifier,test1),ceshi(classifier,test2)))
190 |
191 | >>>好评实例的模型预测情感得分为0.8638082706675478
192 | >>>差评实例的模型预测情感得分为0.7856544482460911
193 | ```
194 |
195 | 点评网上的实际测试中,5星好评模型预测出来了,1星差评缺预测错误。为什么呢?我们查看一下**混淆矩阵**
196 |
197 | ```
198 | [ 46, 385]
199 | [ 8, 4984]
200 | ```
201 |
202 | 可以看出,**负类的预测非常不准**,433单准确预测为负类的只有15.7%,应该是由于**数据不平衡**导致的,模型的默认阈值为输出值的中位数。比如逻辑回归的输出范围为[0,1],当某个样本的输出大于0.5就会被划分为正例,反之为反例。在数据的类别不平衡时,采用默认的分类阈值可能会导致输出全部为正例,产生虚假的高准确度,导致分类失败。
203 |
204 | 处理样本不均衡问题的方法,首先可以选择调整阈值,使得模型对于较少的类别更为敏感,或者选择合适的评估标准,比如ROC或者F1,而不是准确度(accuracy)。另外一种方法就是通过采样(sampling)来调整数据的不平衡。其中欠采样抛弃了大部分正例数据,从而弱化了其影响,可能会造成偏差很大的模型,同时,数据总是宝贵的,抛弃数据是很奢侈的。另外一种是过采样,下面我们就使用过采样方法来调整。
205 |
206 | ### 样本数据不平衡
207 |
208 | 最简单的过采样方法,就是简单复制法。但单纯的重复了反例,会过分强调已有的反例。如果其中部分点标记错误或者是噪音,那么错误也容易被成倍的放大。因此最大的风险就是对反例过拟合。
209 |
210 | ``` python
211 | #把0类样本复制10次,构造训练集
212 | index_tmp = y_train==0
213 | y_tmp = y_train[index_tmp]
214 | x_tmp = x_train[index_tmp]
215 | x_train2 = pd.concat([x_train,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp])
216 | y_train2 = pd.concat([y_train,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp])
217 |
218 | #使用过采样样本(简单复制)进行模型训练,并查看准确率
219 | clf2 = MultinomialNB()
220 | clf2.fit(tv.transform(x_train2), y_train2)
221 | y_pred2 = clf2.predict_proba(tv.transform(x_test))[:,1]
222 | roc_auc_score(y_test,y_pred2)
223 |
224 | >>>0.9049699937533463
225 | ```
226 |
227 | 查看此时的混淆矩阵
228 |
229 | ```
230 | [ 331, 100]
231 | [ 637, 4355]
232 | ```
233 |
234 | 可以看出,即使是简单粗暴的复制样本来处理样本不平衡问题,负样本的识别率大幅上升了,变为77%,满满的幸福感呀。还有SMOTE过采样算法,SMOTE是在局部区域通过K-近邻生成了新的反例。相较于简单的过采样,SMOTE降低了过拟合风险,但同时运算开销加大,详细请看具体代码~
235 |
236 | ### 模型评估测试
237 |
238 | 我们把3W条数据都拿来训练,数据量变多了,模型效果应该会更好
239 |
240 | ``` python
241 | def fenxi(strings):
242 | strings_fenci = fenci(pd.Series([strings]))
243 | return float(clf.predict_proba(tv2.transform(strings_fenci))[:,1])
244 |
245 | #到网上找一条差评来测试一下
246 | fenxi('糯米外皮不绵滑,豆沙馅粗躁,没有香甜味。12元一碗不值。')
247 |
248 | >>>0.28900092243477077
249 | ```
250 |
251 | 只用到了简单的机器学习,就做出了不错的情感分析效果,知识的力量真是强大呀,666~
252 |
253 | ## 四、拓展应用及后续方向
254 |
255 | - 使用更复杂的机器学习模型如神经网络、支持向量机等
256 | - 模型的调参
257 | - 行业词库的构建
258 | - 增加数据量
259 | - 优化情感分析的算法
260 | - 增加标签提取等
261 | - 项目部署到服务器上,更好地分享和测试模型的效果
--------------------------------------------------------------------------------
/__pycache__/mysqls.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-bin/dianping_textmining/9abe0f28881bebc442b638c3606ccd7a3c803632/__pycache__/mysqls.cpython-36.pyc
--------------------------------------------------------------------------------
/大众点评爬虫/CRAW_IP.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | from bs4 import BeautifulSoup
4 |
5 | import lxml
6 |
7 | from multiprocessing import Process, Queue
8 |
9 | import random
10 |
11 | import json
12 |
13 | import time
14 |
15 | import requests
16 |
17 |
18 | class Proxies(object):
19 | """docstring for Proxies"""
20 |
21 | def __init__(self, page=3):
22 |
23 | self.proxies = []
24 |
25 | self.verify_pro = []
26 |
27 | self.page = page
28 |
29 | self.headers = {
30 |
31 | 'Accept': '*/*',
32 |
33 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36',
34 |
35 | 'Accept-Encoding': 'gzip, deflate, sdch',
36 |
37 | 'Accept-Language': 'zh-CN,zh;q=0.8'
38 |
39 | }
40 |
41 | self.get_proxies()
42 |
43 | self.get_proxies_nn()
44 |
45 | def get_proxies(self):
46 |
47 | page = random.randint(1, 10)
48 |
49 | page_stop = page + self.page
50 |
51 | while page < page_stop:
52 |
53 | url = 'http://www.xicidaili.com/nt/%d' % page
54 |
55 | html = requests.get(url, headers=self.headers).content
56 |
57 | soup = BeautifulSoup(html, 'lxml')
58 |
59 | ip_list = soup.find(id='ip_list')
60 |
61 | for odd in ip_list.find_all(class_='odd'):
62 | protocol = odd.find_all('td')[5].get_text().lower() + '://'
63 |
64 | self.proxies.append(protocol + ':'.join([x.get_text() for x in odd.find_all('td')[1:3]]))
65 |
66 | page += 1
67 |
68 | def get_proxies_nn(self):
69 |
70 | page = random.randint(1, 10)
71 |
72 | page_stop = page + self.page
73 |
74 | while page < page_stop:
75 |
76 | url = 'http://www.xicidaili.com/nn/%d' % page
77 |
78 | html = requests.get(url, headers=self.headers).content
79 |
80 | soup = BeautifulSoup(html, 'lxml')
81 |
82 | ip_list = soup.find(id='ip_list')
83 |
84 | for odd in ip_list.find_all(class_='odd'):
85 | protocol = odd.find_all('td')[5].get_text().lower() + '://'
86 |
87 | self.proxies.append(protocol + ':'.join([x.get_text() for x in odd.find_all('td')[1:3]]))
88 |
89 | page += 1
90 |
91 | def verify_proxies(self):
92 |
93 | # 没验证的代理
94 |
95 | old_queue = Queue()
96 |
97 | # 验证后的代理
98 |
99 | new_queue = Queue()
100 |
101 | print('verify proxy........')
102 |
103 | works = []
104 |
105 | for _ in range(15):
106 | works.append(Process(target=self.verify_one_proxy, args=(old_queue, new_queue)))
107 |
108 | for work in works:
109 | work.start()
110 |
111 | for proxy in self.proxies:
112 | old_queue.put(proxy)
113 |
114 | for work in works:
115 | old_queue.put(0)
116 |
117 | for work in works:
118 | work.join()
119 |
120 | self.proxies = []
121 |
122 | while 1:
123 |
124 | try:
125 |
126 | self.proxies.append(new_queue.get(timeout=1))
127 |
128 | except:
129 |
130 | break
131 |
132 | print('verify_proxies done!')
133 |
134 | def verify_one_proxy(self, old_queue, new_queue):
135 |
136 | while 1:
137 |
138 | proxy = old_queue.get()
139 |
140 | if proxy == 0: break
141 |
142 | protocol = 'https' if 'https' in proxy else 'http'
143 |
144 | proxies = {protocol: proxy}
145 |
146 | try:
147 |
148 | if requests.get('http://www.baidu.com', proxies=proxies, timeout=2).status_code == 200:
149 | print('success %s' % proxy)
150 |
151 | new_queue.put(proxy)
152 |
153 | except:
154 |
155 | print('fail %s' % proxy)
156 |
157 |
158 | if __name__ == '__main__':
159 |
160 | a = Proxies()
161 |
162 | a.verify_proxies()
163 |
164 | print(a.proxies)
165 |
166 | proxie = a.proxies
167 |
168 | with open('proxies.txt', 'a') as f:
169 |
170 | for proxy in proxie:
171 | f.write(proxy + '\n')
172 |
173 |
174 |
175 |
176 |
--------------------------------------------------------------------------------
/大众点评爬虫/README.md:
--------------------------------------------------------------------------------
1 | ## 大众点评评论爬虫脚本使用指南
2 |
3 | ### 爬取前的准备
4 |
5 | - mysql数据库安装、打开服务
6 | - 修改mysqls.py程序中数据库的用户名密码等,并创建对应的database和table,可以使用mysqls.creat_table()函数
7 | - 登录大众点评官网,通过谷歌开发者工具等获取到当前的cookie,修改main.py中的cookie变量
8 | - 查看爬取的店铺的店铺ID以及评论的页数,修改main.py 中对应的位置
9 | - 如果有xuchuan.txt(保存当前点评爬取进度),请在爬取前删除(每换一个店铺要删除一次)
10 |
11 | ### 爬取过程中
12 |
13 | - 由于大概每爬取100页左右,需要进行一次验证,当发现获取评论为0条或者异常时,请用浏览器打开点评页面,滑动滑块解锁,然后重启程序,有断点续传,不虚~
14 | - 当更换店铺时,需要把店铺ID进行替换,还有评论的页数也要替换,还要删除xuchuan.txt
15 |
16 | ### 爬取结束后
17 |
18 | 数据存储于MYSQL数据库中,可以使用各种方法读取,啦啦啦啦~
--------------------------------------------------------------------------------
/大众点评爬虫/main.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Mon Jul 9 16:42:52 2018
4 |
5 | @author: bin
6 | """
7 |
8 | #目标爬取店铺的评论
9 |
10 | import requests
11 | from bs4 import BeautifulSoup
12 | import time, random
13 | import mysqls
14 | import re
15 | from fake_useragent import UserAgent
16 | import os
17 |
18 | ua = UserAgent()
19 |
20 | #设置cookies
21 | cookie = "_lxsdk_cuid=162760423dfc8-0801f141cb0731-3b60490d-e1000-162760423dfc8; _lxsdk=162760423dfc8-0801f141cb0731-3b60490d-e1000-162760423dfc8; _hc.v=af7219c3-2b99-8bb8-f9b2-7b1d9be7f29e.1522398406; s_ViewType=10; ua=%E4%BB%A4%E7%8B%90%E5%86%B2; ctu=029e953356caf94d20233d299a70d285a03cb64585c371690b17d3e59c4c075c; cye=guangzhou; Hm_lvt_e6f449471d3527d58c46e24efb4c343e=1531964746; cy=4; dper=8c6ae023e893759ea57ce154028f1800be56b69450806b893b9cf5c6b6c3e3ba3c986c9a603bcbf9a7fb18dcd2038cf704b3e3baba3532bc7dffec965fe5e6c3b2479ca21c6577a1f5636088acbba8936df6ac994e02a923a907907a938559f9; ll=7fd06e815b796be3df069dec7836c3df; _lx_utm=utm_source%3DBaidu%26utm_medium%3Dorganic; _lxsdk_s=1661889a264-50e-66f-22a%7C%7C276"
22 |
23 | #修改请求头
24 | headers = {
25 | 'User-Agent':ua.random,
26 | 'Cookie':cookie,
27 | 'Connection':'keep-alive',
28 | 'Host':'www.dianping.com',
29 | 'Referer': 'http://www.dianping.com/shop/521698/review_all/p6'
30 | }
31 |
32 | #从ip代理池中随机获取ip
33 | #ips = open('proxies.txt','r').read().split('\n')
34 | #
35 | #def get_random_ip():
36 | # ip = random.choice(ips)
37 | # pxs = {ip.split(':')[0]:ip}
38 | # return pxs
39 |
40 | #获取html页面
41 | def getHTMLText(url,code="utf-8"):
42 | try:
43 | time.sleep(random.random()*6 + 2)
44 | r=requests.get(url, timeout = 5, headers=headers,
45 | # proxies=get_random_ip()
46 | )
47 | r.raise_for_status()
48 | r.encoding = code
49 | return r.text
50 | except:
51 | print("产生异常")
52 | return "产生异常"
53 |
54 | #因为评论中带有emoji表情,是4个字符长度的,mysql数据库不支持4个字符长度,因此要进行过滤
55 | def remove_emoji(text):
56 | try:
57 | highpoints = re.compile(u'[\U00010000-\U0010ffff]')
58 | except re.error:
59 | highpoints = re.compile(u'[\uD800-\uDBFF][\uDC00-\uDFFF]')
60 | return highpoints.sub(u'',text)
61 |
62 | #从html中提起所需字段信息
63 | def parsePage(html,shpoID):
64 | infoList = [] #用于存储提取后的信息,列表的每一项都是一个字典
65 | soup = BeautifulSoup(html, "html.parser")
66 |
67 | for item in soup('div','main-review'):
68 | cus_id = item.find('a','name').text.strip()
69 | comment_time = item.find('span','time').text.strip()
70 | try:
71 | comment_star = item.find('span',re.compile('sml-rank-stars')).get('class')[1]
72 | except:
73 | comment_star = 'NAN'
74 | cus_comment = item.find('div',"review-words").text.strip()
75 | scores = str(item.find('span','score'))
76 | try:
77 | kouwei = re.findall(r'口味:([\u4e00-\u9fa5]*)',scores)[0]
78 | huanjing = re.findall(r'环境:([\u4e00-\u9fa5]*)',scores)[0]
79 | fuwu = re.findall(r'服务:([\u4e00-\u9fa5]*)',scores)[0]
80 | except:
81 | kouwei = huanjing = fuwu = '无'
82 |
83 | infoList.append({'cus_id':cus_id,
84 | 'comment_time':comment_time,
85 | 'comment_star':comment_star,
86 | 'cus_comment':remove_emoji(cus_comment),
87 | 'kouwei':kouwei,
88 | 'huanjing':huanjing,
89 | 'fuwu':fuwu,
90 | 'shopID':shpoID})
91 | return infoList
92 |
93 | #构造每一页的url,并且对爬取的信息进行存储
94 | def getCommentinfo(shop_url, shpoID, page_begin, page_end):
95 | for i in range(page_begin, page_end):
96 | try:
97 | url = shop_url + 'p' + str(i)
98 | html = getHTMLText(url)
99 | infoList = parsePage(html,shpoID)
100 | print('成功爬取第{}页数据,有评论{}条'.format(i,len(infoList)))
101 | for info in infoList:
102 | mysqls.save_data(info)
103 | #断点续传中的断点
104 | if (html != "产生异常") and (len(infoList) != 0):
105 | with open('xuchuan.txt','a') as file:
106 | duandian = str(i)+'\n'
107 | file.write(duandian)
108 | else:
109 | print('休息60s...')
110 | time.sleep(60)
111 | except:
112 | print('跳过本次')
113 | continue
114 | return
115 |
116 | def xuchuan():
117 | if os.path.exists('xuchuan.txt'):
118 | file = open('xuchuan.txt','r')
119 | nowpage = int(file.readlines()[-1])
120 | file.close()
121 | else:
122 | nowpage = 0
123 | return nowpage
124 |
125 | #根据店铺id,店铺页码进行爬取
126 | def craw_comment(shopID='521698',page = 53):
127 | shop_url = "http://www.dianping.com/shop/" + shopID + "/review_all/"
128 | #读取断点续传中的续传断点
129 | nowpage = xuchuan()
130 | getCommentinfo(shop_url, shopID, page_begin=nowpage+1, page_end=page+1)
131 | mysqls.close_sql()
132 | return
133 |
134 | if __name__ == "__main__":
135 | craw_comment()
136 |
--------------------------------------------------------------------------------
/大众点评爬虫/mysqls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Tue Jul 24 15:45:05 2018
4 |
5 | @author: bin
6 | """
7 |
8 | import pymysql
9 |
10 | #连接MYSQL数据库
11 | db = pymysql.connect("localhost","root","","TESTDB" )
12 | cursor = db.cursor()
13 |
14 | #在数据库建表
15 | def creat_table():
16 | cursor.execute("DROP TABLE IF EXISTS DZDP")
17 | sql = '''CREATE TABLE DZDP(
18 | cus_id varchar(100),
19 | comment_time varchar(55),
20 | comment_star varchar(55),
21 | cus_comment text(5000),
22 | kouwei varchar(55),
23 | huanjing varchar(55),
24 | fuwu varchar(55),
25 | shopID varchar(55)
26 | );'''
27 | cursor.execute(sql)
28 | return
29 |
30 | #存储爬取到的数据
31 | def save_data(data_dict):
32 | sql = '''INSERT INTO DZDP(cus_id,comment_time,comment_star,cus_comment,kouwei,huanjing,fuwu,shopID) VALUES(%s,%s,%s,%s,%s,%s,%s,%s)'''
33 | value_tup = (data_dict['cus_id']
34 | ,data_dict['comment_time']
35 | ,data_dict['comment_star']
36 | ,data_dict['cus_comment']
37 | ,data_dict['kouwei']
38 | ,data_dict['huanjing']
39 | ,data_dict['fuwu']
40 | ,data_dict['shopID']
41 | )
42 | try:
43 | cursor.execute(sql,value_tup)
44 | db.commit()
45 | except:
46 | print('数据库写入失败')
47 | return
48 |
49 | #关闭数据库
50 | def close_sql():
51 | db.close()
52 |
--------------------------------------------------------------------------------
/大众点评爬虫/proxies.txt:
--------------------------------------------------------------------------------
1 | https://59.37.18.243:3128
2 | https://183.129.207.74:14823
3 | https://49.73.6.90:3128
4 | https://115.239.255.190:3128
5 | https://203.86.26.9:3128
6 | https://120.92.74.189:3128
7 | http://183.62.196.10:3128
8 | https://183.129.244.17:10010
9 | https://171.221.239.11:808
10 | https://14.29.32.106:53281
11 | https://218.60.8.83:3129
12 | https://183.129.207.80:21776
13 | https://203.130.46.108:9090
14 | https://183.21.81.58:40539
15 | https://182.18.13.149:53281
16 | https://114.113.126.83:80
17 | https://118.212.95.34:53281
18 | https://114.113.126.82:80
19 | https://183.129.207.78:18118
20 | https://211.101.136.86:8080
21 | https://114.249.112.16:9000
22 | https://163.125.68.149:8888
23 | https://111.202.37.195:8080
24 | https://61.145.203.234:38695
25 | https://119.254.94.92:48494
26 | https://27.46.20.55:888
27 | https://175.6.2.174:8088
28 | https://59.72.126.3:8123
29 | https://59.37.26.226:8080
30 | https://120.27.14.125:80
31 | https://61.140.108.57:54689
32 | https://58.240.220.86:53281
33 | https://183.30.201.8:9797
34 | https://111.170.156.182:53281
35 | https://218.15.25.157:8088
36 | https://180.173.152.33:9000
37 | https://117.35.51.77:53281
38 | https://119.90.126.106:7777
39 | https://121.228.125.27:3128
40 | https://218.89.222.110:9999
41 | https://61.155.112.228:61591
42 | https://171.37.30.82:9797
43 | https://125.123.122.59:9000
44 | https://125.123.143.171:9000
45 | https://60.191.57.79:3128
46 | https://163.125.19.43:9999
47 | https://112.65.19.122:8080
48 | https://163.125.17.241:8888
49 | https://163.125.17.238:8888
50 | https://180.213.181.96:8118
51 | https://114.86.227.164:33657
52 | https://118.187.50.154:8080
53 | https://118.190.217.182:80
54 | https://118.190.217.61:80
55 | http://183.129.244.13:10800
56 | https://125.123.127.24:9000
57 | https://124.237.83.14:53281
58 | https://163.125.74.243:9797
59 | https://61.175.172.216:8123
60 | https://175.152.223.235:8123
61 | https://123.165.115.55:9797
62 | https://223.245.127.165:44765
63 | https://59.78.1.5:1080
64 | https://118.25.177.187:1080
65 | https://59.39.196.122:55637
66 | https://119.4.172.217:8118
67 | https://116.30.123.148:9000
68 | https://112.74.207.50:3128
69 | https://14.149.68.120:1080
70 | https://58.251.233.122:9797
71 | https://182.88.187.149:9797
72 | https://182.150.63.89:46073
73 | https://163.125.70.70:9999
74 | https://58.251.234.137:9797
75 | https://101.132.122.230:3128
76 | https://119.129.98.65:45522
77 | https://112.81.143.172:8118
78 | https://220.184.129.224:3128
79 | https://112.250.109.173:53281
80 | https://116.196.92.155:1080
81 | https://14.20.235.117:808
82 | https://182.88.187.83:9797
83 | https://110.52.8.171:53281
84 | https://159.226.170.42:3128
85 | https://121.9.199.70:32431
86 | https://113.118.201.133:9797
87 | https://58.250.23.210:1080
88 | https://119.250.26.39:9000
89 | https://171.36.179.27:9797
90 | https://175.25.185.57:3128
91 | https://118.190.155.23:80
92 | https://114.119.116.93:61066
93 | https://171.36.210.248:9797
94 | https://112.193.130.123:8118
95 | https://123.183.11.166:53386
96 | https://118.186.2.210:8080
97 | https://112.64.38.161:51099
98 | https://222.186.45.146:63756
99 | https://183.14.76.165:9797
100 | https://163.125.19.88:9999
101 | https://218.6.16.233:8118
102 | https://180.168.210.132:80
103 | https://61.164.39.69:53281
104 | https://61.130.9.249:3128
105 | https://122.143.117.8:8080
106 | https://180.162.34.149:9797
107 | https://115.231.50.10:53281
108 | https://112.95.205.63:8888
109 | https://112.95.205.71:8888
110 | https://115.151.4.6:53128
111 | https://110.73.40.17:8123
112 | https://121.207.0.115:808
113 | https://118.180.85.201:8123
114 | https://61.157.206.182:60460
115 | https://124.200.104.234:47076
116 | https://61.157.206.170:42379
117 | https://221.234.192.10:8010
118 | https://59.32.37.7:3128
119 | https://1.183.163.137:53077
120 | https://59.49.22.231:30151
121 | https://27.22.104.28:39560
122 | https://61.160.233.214:39522
123 | https://59.32.37.246:8010
124 | https://115.46.79.110:8123
125 | https://110.73.10.53:8123
126 | https://110.73.43.173:8123
127 | https://183.63.17.253:54174
128 | https://121.9.199.51:59134
129 | https://123.163.20.37:35249
130 | https://61.158.187.118:56524
131 | https://61.157.206.187:37667
132 | https://203.93.125.238:51108
133 | https://223.203.0.14:8080
134 | https://221.224.62.243:51941
135 | https://114.225.169.161:53128
136 | https://124.77.92.239:31307
137 | https://27.153.128.207:8010
138 | https://110.188.0.64:35137
139 | https://115.238.105.108:808
140 | https://61.133.245.70:35652
141 | https://60.211.192.54:40700
142 | https://171.37.155.232:8123
143 | https://221.232.193.223:8010
144 | https://27.190.26.57:8118
145 | https://221.224.212.11:23500
146 | https://180.118.240.51:61234
147 | https://113.106.97.148:38257
148 | https://119.97.23.87:8123
149 | https://1.183.163.101:52524
150 | https://61.157.206.172:59656
151 | https://121.205.254.201:8010
152 | https://61.157.206.178:34692
153 | https://115.46.74.160:8123
154 | https://120.5.162.224:32290
155 | https://61.154.49.38:59675
156 | https://61.160.233.215:48478
157 | https://119.123.77.41:31425
158 | https://114.225.170.217:53128
159 | https://113.17.36.96:47399
160 | https://114.112.70.150:57871
161 | https://123.207.30.131:80
162 | https://119.254.94.97:41697
163 | https://115.46.73.129:8123
164 | https://115.221.112.122:25903
165 | https://115.211.231.66:8010
166 | https://221.232.192.206:8010
167 | https://182.88.166.78:8123
168 | https://115.46.67.43:8123
169 | https://121.205.254.192:808
170 | https://175.148.73.231:1133
171 | https://183.129.153.122:36839
172 | https://139.196.111.17:42589
173 | https://60.12.214.184:33507
174 | https://117.85.86.73:53128
175 | https://115.46.77.225:8123
176 | https://121.31.177.217:8123
177 | https://110.73.42.191:8123
178 | https://222.85.22.167:8010
179 | https://119.48.97.137:80
180 | https://218.79.113.92:30366
181 | https://101.236.55.145:8866
182 | https://116.235.75.177:61922
183 | https://220.248.125.82:8118
184 | https://121.60.76.28:8010
185 | https://116.17.236.52:8010
186 | https://115.223.114.224:8010
187 | https://122.246.51.176:8010
188 | https://59.45.27.245:50858
189 | https://171.37.153.33:8123
190 | https://121.225.26.218:3128
191 | https://180.118.243.93:61234
192 | https://115.46.78.208:8123
193 | https://175.148.76.72:1133
194 | https://223.244.252.58:45744
195 | https://115.223.117.127:8010
196 | https://59.46.112.34:43858
197 | https://117.114.144.195:35070
198 | https://180.118.243.52:61234
199 | https://180.110.7.46:3128
200 | https://106.42.208.201:8010
201 | https://42.236.151.226:37848
202 | https://221.2.207.205:51030
203 | https://114.80.216.171:54408
204 | https://119.254.94.95:43150
205 | https://121.31.153.170:8123
206 | https://113.121.242.173:808
207 | https://122.138.16.158:80
208 | https://182.88.129.168:8123
209 | https://113.200.27.10:53281
210 |
--------------------------------------------------------------------------------
/大众点评爬虫/xuchuan.txt:
--------------------------------------------------------------------------------
1 | 1
2 | 2
3 | 3
4 | 4
5 | 5
6 | 6
7 | 7
8 | 8
9 | 9
10 | 10
11 | 11
12 | 12
13 | 13
14 | 14
15 | 15
16 | 16
17 | 17
18 | 18
19 | 19
20 | 20
21 | 21
22 | 22
23 | 23
24 | 24
25 | 25
26 | 26
27 | 27
28 | 28
29 | 29
30 | 30
31 | 31
32 | 32
33 | 33
34 | 34
35 | 35
36 | 36
37 | 37
38 | 38
39 | 39
40 | 40
41 | 41
42 | 42
43 | 43
44 | 44
45 | 45
46 | 46
47 | 47
48 | 48
49 | 49
50 | 50
51 | 51
52 | 52
53 | 53
54 |
--------------------------------------------------------------------------------
/文本分析挖掘/.ipynb_checkpoints/Untitled-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 51,
6 | "metadata": {
7 | "collapsed": true
8 | },
9 | "outputs": [],
10 | "source": [
11 | "import pandas as pd\n",
12 | "from matplotlib import pyplot as plt\n",
13 | "import jieba"
14 | ]
15 | },
16 | {
17 | "cell_type": "code",
18 | "execution_count": 52,
19 | "metadata": {},
20 | "outputs": [
21 | {
22 | "data": {
23 | "text/html": [
24 | "
\n",
25 | "\n",
38 | "
\n",
39 | " \n",
40 | " \n",
41 | " | \n",
42 | " cus_id | \n",
43 | " comment_time | \n",
44 | " comment_star | \n",
45 | " cus_comment | \n",
46 | " kouwei | \n",
47 | " huanjing | \n",
48 | " fuwu | \n",
49 | " shopID | \n",
50 | " stars | \n",
51 | " year | \n",
52 | " month | \n",
53 | " weekday | \n",
54 | " hour | \n",
55 | " comment_len | \n",
56 | "
\n",
57 | " \n",
58 | " \n",
59 | " \n",
60 | " 0 | \n",
61 | " 迷糊泰迪 | \n",
62 | " 2018-09-20 06:48:00 | \n",
63 | " sml-str40 | \n",
64 | " 南信 算是 广州 著名 甜品店吧 ,好几个 时间段 路过 ,都是 座无虚席。 看着 餐单 ... | \n",
65 | " 非常好 | \n",
66 | " 好 | \n",
67 | " 好 | \n",
68 | " 518986.0 | \n",
69 | " 4.0 | \n",
70 | " 2018.0 | \n",
71 | " 9.0 | \n",
72 | " 3.0 | \n",
73 | " 6.0 | \n",
74 | " 184.0 | \n",
75 | "
\n",
76 | " \n",
77 | " 1 | \n",
78 | " 稱霸幼稚園 | \n",
79 | " 2018-09-22 21:49:00 | \n",
80 | " sml-str40 | \n",
81 | " 中午吃完了所谓的早茶 回去放下行李 休息了会 就来吃下午茶了[服务]两层楼 楼下只能收现金... | \n",
82 | " 很好 | \n",
83 | " 很好 | \n",
84 | " 很好 | \n",
85 | " 518986.0 | \n",
86 | " 4.0 | \n",
87 | " 2018.0 | \n",
88 | " 9.0 | \n",
89 | " 5.0 | \n",
90 | " 21.0 | \n",
91 | " 266.0 | \n",
92 | "
\n",
93 | " \n",
94 | " 2 | \n",
95 | " 爱吃的美美侠 | \n",
96 | " 2018-09-22 22:16:00 | \n",
97 | " sml-str40 | \n",
98 | " 【VIP冲刺王者战队】【吃遍蓉城战队】【VIP有特权】五月份和好朋友毕业旅行来了广州。我们都... | \n",
99 | " 很好 | \n",
100 | " 很好 | \n",
101 | " 很好 | \n",
102 | " 518986.0 | \n",
103 | " 4.0 | \n",
104 | " 2018.0 | \n",
105 | " 9.0 | \n",
106 | " 5.0 | \n",
107 | " 22.0 | \n",
108 | " 341.0 | \n",
109 | "
\n",
110 | " \n",
111 | " 3 | \n",
112 | " 姜姜会吃胖 | \n",
113 | " 2018-09-19 06:36:00 | \n",
114 | " sml-str40 | \n",
115 | " 都说来广州吃糖水就要来南信招牌姜撞奶,红豆双皮奶牛三星,云吞面一楼现金,二楼微信支付宝位置不... | \n",
116 | " 非常好 | \n",
117 | " 很好 | \n",
118 | " 很好 | \n",
119 | " 518986.0 | \n",
120 | " 4.0 | \n",
121 | " 2018.0 | \n",
122 | " 9.0 | \n",
123 | " 2.0 | \n",
124 | " 6.0 | \n",
125 | " 197.0 | \n",
126 | "
\n",
127 | " \n",
128 | " 4 | \n",
129 | " forevercage | \n",
130 | " 2018-08-24 17:58:00 | \n",
131 | " sml-str50 | \n",
132 | " 一直很期待也最爱吃甜品,广州的甜品很丰富很多样,来之前就一直想着一定要过来吃到腻,今天总算实... | \n",
133 | " 非常好 | \n",
134 | " 很好 | \n",
135 | " 很好 | \n",
136 | " 518986.0 | \n",
137 | " 5.0 | \n",
138 | " 2018.0 | \n",
139 | " 8.0 | \n",
140 | " 4.0 | \n",
141 | " 17.0 | \n",
142 | " 261.0 | \n",
143 | "
\n",
144 | " \n",
145 | "
\n",
146 | "
"
147 | ],
148 | "text/plain": [
149 | " cus_id comment_time comment_star \\\n",
150 | "0 迷糊泰迪 2018-09-20 06:48:00 sml-str40 \n",
151 | "1 稱霸幼稚園 2018-09-22 21:49:00 sml-str40 \n",
152 | "2 爱吃的美美侠 2018-09-22 22:16:00 sml-str40 \n",
153 | "3 姜姜会吃胖 2018-09-19 06:36:00 sml-str40 \n",
154 | "4 forevercage 2018-08-24 17:58:00 sml-str50 \n",
155 | "\n",
156 | " cus_comment kouwei huanjing fuwu \\\n",
157 | "0 南信 算是 广州 著名 甜品店吧 ,好几个 时间段 路过 ,都是 座无虚席。 看着 餐单 ... 非常好 好 好 \n",
158 | "1 中午吃完了所谓的早茶 回去放下行李 休息了会 就来吃下午茶了[服务]两层楼 楼下只能收现金... 很好 很好 很好 \n",
159 | "2 【VIP冲刺王者战队】【吃遍蓉城战队】【VIP有特权】五月份和好朋友毕业旅行来了广州。我们都... 很好 很好 很好 \n",
160 | "3 都说来广州吃糖水就要来南信招牌姜撞奶,红豆双皮奶牛三星,云吞面一楼现金,二楼微信支付宝位置不... 非常好 很好 很好 \n",
161 | "4 一直很期待也最爱吃甜品,广州的甜品很丰富很多样,来之前就一直想着一定要过来吃到腻,今天总算实... 非常好 很好 很好 \n",
162 | "\n",
163 | " shopID stars year month weekday hour comment_len \n",
164 | "0 518986.0 4.0 2018.0 9.0 3.0 6.0 184.0 \n",
165 | "1 518986.0 4.0 2018.0 9.0 5.0 21.0 266.0 \n",
166 | "2 518986.0 4.0 2018.0 9.0 5.0 22.0 341.0 \n",
167 | "3 518986.0 4.0 2018.0 9.0 2.0 6.0 197.0 \n",
168 | "4 518986.0 5.0 2018.0 8.0 4.0 17.0 261.0 "
169 | ]
170 | },
171 | "execution_count": 52,
172 | "metadata": {},
173 | "output_type": "execute_result"
174 | }
175 | ],
176 | "source": [
177 | "data = pd.read_csv('data.csv')\n",
178 | "data.head()"
179 | ]
180 | },
181 | {
182 | "cell_type": "code",
183 | "execution_count": 53,
184 | "metadata": {
185 | "collapsed": true
186 | },
187 | "outputs": [],
188 | "source": [
189 | "#构建特征值\n",
190 | "def zhuanhuan(score):\n",
191 | " if score > 3:\n",
192 | " return 1\n",
193 | " elif score < 3:\n",
194 | " return 0\n",
195 | " else:\n",
196 | " return None"
197 | ]
198 | },
199 | {
200 | "cell_type": "code",
201 | "execution_count": 70,
202 | "metadata": {},
203 | "outputs": [],
204 | "source": [
205 | "#特征值转换\n",
206 | "data['target'] = data['stars'].map(lambda x:zhuanhuan(x))\n",
207 | "data_model = data.dropna()"
208 | ]
209 | },
210 | {
211 | "cell_type": "code",
212 | "execution_count": 76,
213 | "metadata": {},
214 | "outputs": [],
215 | "source": [
216 | "#切分测试集、训练集\n",
217 | "from sklearn.model_selection import train_test_split\n",
218 | "x_train, x_test, y_train, y_test = train_test_split(data_model['cus_comment'], data_model['target'], random_state=1, test_size=0.25)"
219 | ]
220 | },
221 | {
222 | "cell_type": "code",
223 | "execution_count": 77,
224 | "metadata": {
225 | "collapsed": true
226 | },
227 | "outputs": [],
228 | "source": [
229 | "#引入停用词\n",
230 | "infile = open(\"stopwords.txt\",encoding='utf-8')\n",
231 | "stopwords_lst = infile.readlines()\n",
232 | "stopwords = [x.strip() for x in stopwords_lst]"
233 | ]
234 | },
235 | {
236 | "cell_type": "code",
237 | "execution_count": 78,
238 | "metadata": {},
239 | "outputs": [
240 | {
241 | "data": {
242 | "text/plain": [
243 | "16464 简单 的 店面 , 甜品 种类 超多 , 选择 困难 , 点 了 红豆 薏米 芋头 , 还 ...\n",
244 | "28132 打算 去 长隆 玩水 在 番禺 附近 搜到 的 店 , 离住 的 地方 很近 , 大热天 走...\n",
245 | "14213 甜品 第一站 当然 是 选 在 百花 甜品 了 , 光听 这个 名字 就 可以 想象 种类 ...\n",
246 | "24829 在 大众 点评 看到 推荐 的 同福路 美食 , 刚刚 和 朋友 闲逛 来到 同福路 , 决...\n",
247 | "31055 几乎 每次 去 广州 都 会 去 这间 店 吃 甜品 , 非常 不错 的 一间 店 , 环境...\n",
248 | "Name: cus_comment, dtype: object"
249 | ]
250 | },
251 | "execution_count": 78,
252 | "metadata": {},
253 | "output_type": "execute_result"
254 | }
255 | ],
256 | "source": [
257 | "#中文分词\n",
258 | "def fenci(train_data):\n",
259 | " words_df = train_data.apply(lambda x:' '.join(jieba.cut(x)))\n",
260 | " return words_df\n",
261 | " \n",
262 | "x_train_fenci = fenci(x_train)\n",
263 | "x_train_fenci[:5]"
264 | ]
265 | },
266 | {
267 | "cell_type": "code",
268 | "execution_count": 79,
269 | "metadata": {},
270 | "outputs": [
271 | {
272 | "data": {
273 | "text/plain": [
274 | "TfidfVectorizer(analyzer='word', binary=False, decode_error='strict',\n",
275 | " dtype=, encoding='utf-8', input='content',\n",
276 | " lowercase=True, max_df=1.0, max_features=3000, min_df=1,\n",
277 | " ngram_range=(1, 2), norm='l2', preprocessor=None, smooth_idf=True,\n",
278 | " stop_words=['!', '\"', '#', '$', '%', '&', \"'\", '(', ')', '*', '+', ',', '-', '--', '.', '..', '...', '......', '...................', './', '.一', '记者', '数', '年', '月', '日', '时', '分', '秒', '/', '//', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '://', '::', ';', '<', '=', '>', '>>', '?', '@'...3', '94', '95', '96', '97', '98', '99', '100', '01', '02', '03', '04', '05', '06', '07', '08', '09'],\n",
279 | " strip_accents=None, sublinear_tf=False,\n",
280 | " token_pattern='(?u)\\\\b\\\\w\\\\w+\\\\b', tokenizer=None, use_idf=True,\n",
281 | " vocabulary=None)"
282 | ]
283 | },
284 | "execution_count": 79,
285 | "metadata": {},
286 | "output_type": "execute_result"
287 | }
288 | ],
289 | "source": [
290 | "from sklearn.feature_extraction.text import TfidfVectorizer\n",
291 | "tv = TfidfVectorizer(stop_words=stopwords, max_features=3000, ngram_range=(1,2))\n",
292 | "tv.fit(x_train_fenci)"
293 | ]
294 | },
295 | {
296 | "cell_type": "code",
297 | "execution_count": 80,
298 | "metadata": {},
299 | "outputs": [
300 | {
301 | "data": {
302 | "text/plain": [
303 | "0.93196902654867253"
304 | ]
305 | },
306 | "execution_count": 80,
307 | "metadata": {},
308 | "output_type": "execute_result"
309 | }
310 | ],
311 | "source": [
312 | "from sklearn.naive_bayes import MultinomialNB\n",
313 | "classifier = MultinomialNB()\n",
314 | "classifier.fit(tv.transform(fenci(x_train)), y_train)\n",
315 | "classifier.score(tv.transform(fenci(x_test)), y_test)"
316 | ]
317 | },
318 | {
319 | "cell_type": "code",
320 | "execution_count": 81,
321 | "metadata": {
322 | "scrolled": true
323 | },
324 | "outputs": [
325 | {
326 | "data": {
327 | "text/plain": [
328 | "0.89689292921253627"
329 | ]
330 | },
331 | "execution_count": 81,
332 | "metadata": {},
333 | "output_type": "execute_result"
334 | }
335 | ],
336 | "source": [
337 | "from sklearn.metrics import roc_auc_score\n",
338 | "y_pred = classifier.predict_proba(tv.transform(fenci(x_test)))[:,1]\n",
339 | "roc_auc_score(y_test,y_pred)"
340 | ]
341 | },
342 | {
343 | "cell_type": "markdown",
344 | "metadata": {},
345 | "source": [
346 | "查看混淆矩阵"
347 | ]
348 | },
349 | {
350 | "cell_type": "code",
351 | "execution_count": 92,
352 | "metadata": {
353 | "collapsed": true
354 | },
355 | "outputs": [],
356 | "source": [
357 | "y_predict = classifier.predict(tv.transform(fenci(x_test)))"
358 | ]
359 | },
360 | {
361 | "cell_type": "code",
362 | "execution_count": 94,
363 | "metadata": {
364 | "scrolled": true
365 | },
366 | "outputs": [
367 | {
368 | "data": {
369 | "text/plain": [
370 | "array([[ 68, 365],\n",
371 | " [ 4, 4987]])"
372 | ]
373 | },
374 | "execution_count": 94,
375 | "metadata": {},
376 | "output_type": "execute_result"
377 | }
378 | ],
379 | "source": [
380 | "from sklearn.metrics import confusion_matrix\n",
381 | "cm = confusion_matrix(y_test, y_predict)\n",
382 | "cm"
383 | ]
384 | },
385 | {
386 | "cell_type": "markdown",
387 | "metadata": {},
388 | "source": [
389 | "可以看出,负类的预测非常不准,433单准确预测为负类的只有15.7%,应该是由于数据不平衡导致的,接下来我们就解决一下这个问题"
390 | ]
391 | },
392 | {
393 | "cell_type": "code",
394 | "execution_count": 118,
395 | "metadata": {},
396 | "outputs": [],
397 | "source": [
398 | "data2 = data.loc[(data['stars'] == 1)|(data['stars'] == 2)].copy()\n",
399 | "data3 = pd.concat([data_model,data2,data2,data2,data2,data2,data2,data2,data2,data2,data2],axis=0)\n",
400 | "x_train, x_test, y_train, y_test = train_test_split(data3['cus_comment'], data3['target'], random_state=1, test_size=0.25)"
401 | ]
402 | },
403 | {
404 | "cell_type": "code",
405 | "execution_count": 119,
406 | "metadata": {},
407 | "outputs": [
408 | {
409 | "ename": "ValueError",
410 | "evalue": "np.nan is an invalid document, expected byte or unicode string.",
411 | "output_type": "error",
412 | "traceback": [
413 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
414 | "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
415 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mtv2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mTfidfVectorizer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstop_words\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mstopwords\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmax_features\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m3000\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mngram_range\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mtv2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'cus_comment'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[0mclf2\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mMultinomialNB\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mclf2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtv2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtransform\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfenci\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'cus_comment'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdata3\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'target'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
416 | "\u001b[1;32mD:\\SOFTWARE\\Anaconda\\lib\\site-packages\\sklearn\\feature_extraction\\text.py\u001b[0m in \u001b[0;36mfit\u001b[1;34m(self, raw_documents, y)\u001b[0m\n\u001b[0;32m 1330\u001b[0m \u001b[0mself\u001b[0m \u001b[1;33m:\u001b[0m \u001b[0mTfidfVectorizer\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1331\u001b[0m \"\"\"\n\u001b[1;32m-> 1332\u001b[1;33m \u001b[0mX\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msuper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mTfidfVectorizer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfit_transform\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mraw_documents\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 1333\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_tfidf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfit\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mX\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1334\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
417 | "\u001b[1;32mD:\\SOFTWARE\\Anaconda\\lib\\site-packages\\sklearn\\feature_extraction\\text.py\u001b[0m in \u001b[0;36mfit_transform\u001b[1;34m(self, raw_documents, y)\u001b[0m\n\u001b[0;32m 837\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 838\u001b[0m vocabulary, X = self._count_vocab(raw_documents,\n\u001b[1;32m--> 839\u001b[1;33m self.fixed_vocabulary_)\n\u001b[0m\u001b[0;32m 840\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 841\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbinary\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
418 | "\u001b[1;32mD:\\SOFTWARE\\Anaconda\\lib\\site-packages\\sklearn\\feature_extraction\\text.py\u001b[0m in \u001b[0;36m_count_vocab\u001b[1;34m(self, raw_documents, fixed_vocab)\u001b[0m\n\u001b[0;32m 760\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mdoc\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mraw_documents\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 761\u001b[0m \u001b[0mfeature_counter\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 762\u001b[1;33m \u001b[1;32mfor\u001b[0m \u001b[0mfeature\u001b[0m \u001b[1;32min\u001b[0m \u001b[0manalyze\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdoc\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 763\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 764\u001b[0m \u001b[0mfeature_idx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mvocabulary\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mfeature\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
419 | "\u001b[1;32mD:\\SOFTWARE\\Anaconda\\lib\\site-packages\\sklearn\\feature_extraction\\text.py\u001b[0m in \u001b[0;36m\u001b[1;34m(doc)\u001b[0m\n\u001b[0;32m 239\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 240\u001b[0m return lambda doc: self._word_ngrams(\n\u001b[1;32m--> 241\u001b[1;33m tokenize(preprocess(self.decode(doc))), stop_words)\n\u001b[0m\u001b[0;32m 242\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 243\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
420 | "\u001b[1;32mD:\\SOFTWARE\\Anaconda\\lib\\site-packages\\sklearn\\feature_extraction\\text.py\u001b[0m in \u001b[0;36mdecode\u001b[1;34m(self, doc)\u001b[0m\n\u001b[0;32m 119\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 120\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mdoc\u001b[0m \u001b[1;32mis\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnan\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 121\u001b[1;33m raise ValueError(\"np.nan is an invalid document, expected byte or \"\n\u001b[0m\u001b[0;32m 122\u001b[0m \"unicode string.\")\n\u001b[0;32m 123\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
421 | "\u001b[1;31mValueError\u001b[0m: np.nan is an invalid document, expected byte or unicode string."
422 | ]
423 | }
424 | ],
425 | "source": [
426 | "tv2 = TfidfVectorizer(stop_words=stopwords, max_features=3000, ngram_range=(1,2))\n",
427 | "tv2.fit(data3['cus_comment'])\n",
428 | "clf2 = MultinomialNB()\n",
429 | "clf2.fit(tv2.transform(fenci(data3['cus_comment'])), data3['target'])"
430 | ]
431 | },
432 | {
433 | "cell_type": "markdown",
434 | "metadata": {},
435 | "source": [
436 | "使用全部数据进行训练"
437 | ]
438 | },
439 | {
440 | "cell_type": "code",
441 | "execution_count": 82,
442 | "metadata": {},
443 | "outputs": [
444 | {
445 | "data": {
446 | "text/plain": [
447 | "MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)"
448 | ]
449 | },
450 | "execution_count": 82,
451 | "metadata": {},
452 | "output_type": "execute_result"
453 | }
454 | ],
455 | "source": [
456 | "tv2 = TfidfVectorizer(stop_words=stopwords, max_features=3000, ngram_range=(1,2))\n",
457 | "tv2.fit(data_model['cus_comment'])\n",
458 | "clf = MultinomialNB()\n",
459 | "clf.fit(tv2.transform(fenci(data_model['cus_comment'])), data_model['target'])"
460 | ]
461 | },
462 | {
463 | "cell_type": "code",
464 | "execution_count": 83,
465 | "metadata": {
466 | "collapsed": true
467 | },
468 | "outputs": [],
469 | "source": [
470 | "def fenxi(strings):\n",
471 | " strings_fenci = fenci(pd.Series([strings]))\n",
472 | " return float(clf.predict_proba(tv2.transform(fenci(strings_fenci)))[:,1])"
473 | ]
474 | }
475 | ],
476 | "metadata": {
477 | "kernelspec": {
478 | "display_name": "Python 3",
479 | "language": "python",
480 | "name": "python3"
481 | },
482 | "language_info": {
483 | "codemirror_mode": {
484 | "name": "ipython",
485 | "version": 3
486 | },
487 | "file_extension": ".py",
488 | "mimetype": "text/x-python",
489 | "name": "python",
490 | "nbconvert_exporter": "python",
491 | "pygments_lexer": "ipython3",
492 | "version": "3.6.6"
493 | }
494 | },
495 | "nbformat": 4,
496 | "nbformat_minor": 2
497 | }
498 |
--------------------------------------------------------------------------------
/文本分析挖掘/.ipynb_checkpoints/Untitled1-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [],
3 | "metadata": {},
4 | "nbformat": 4,
5 | "nbformat_minor": 2
6 | }
7 |
--------------------------------------------------------------------------------
/文本分析挖掘/.ipynb_checkpoints/文本挖掘&情感分析-checkpoint.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# 大众点评评价情感分析~\n",
8 | "先上结果:\n",
9 | "\n",
10 | "| 糖水店的评论文本 | 模型预测的情感评分 |\n",
11 | "| :------------------------------------------- | :----------------- |\n",
12 | "| '糖水味道不错,滑而不腻,赞一个,下次还会来' | 0.91 |\n",
13 | "| '味道一般,没啥特点' | 0.52 |\n",
14 | "| '排队老半天,环境很差,味道一般般' | 0.05 |\n",
15 | "\n",
16 | "模型的效果还可以的样子,yeah~接下来我们好好讲讲怎么做的哈,我们通过爬虫爬取了大众点评广州8家最热门糖水店的3W条评论信息以及评分作为训练数据,前面的分析我们得知*样本很不均衡*。接下来我们的整体思路就是:文本特征处理(分词、去停用词、TF-IDF)—机器学习建模—模型评价。\n",
17 | "\n",
18 | "我们先不处理样本不均衡问题,直接建模后查看结果,接下来我们再按照两种方法处理样本不均衡,对比结果。\n",
19 | "\n",
20 | "### 数据读入和探索"
21 | ]
22 | },
23 | {
24 | "cell_type": "code",
25 | "execution_count": 26,
26 | "metadata": {
27 | "scrolled": true
28 | },
29 | "outputs": [
30 | {
31 | "data": {
32 | "text/html": [
33 | "\n",
34 | "\n",
47 | "
\n",
48 | " \n",
49 | " \n",
50 | " | \n",
51 | " cus_id | \n",
52 | " comment_time | \n",
53 | " comment_star | \n",
54 | " cus_comment | \n",
55 | " kouwei | \n",
56 | " huanjing | \n",
57 | " fuwu | \n",
58 | " shopID | \n",
59 | " stars | \n",
60 | " year | \n",
61 | " month | \n",
62 | " weekday | \n",
63 | " hour | \n",
64 | " comment_len | \n",
65 | " cus_comment_processed | \n",
66 | "
\n",
67 | " \n",
68 | " \n",
69 | " \n",
70 | " 0 | \n",
71 | " 迷糊泰迪 | \n",
72 | " 2018-09-20 06:48:00 | \n",
73 | " sml-str40 | \n",
74 | " 南信 算是 广州 著名 甜品店 吧 好几个 时间段 路过 都 是 座无虚席 看着 餐单 上 ... | \n",
75 | " 非常好 | \n",
76 | " 好 | \n",
77 | " 好 | \n",
78 | " 518986 | \n",
79 | " 4.0 | \n",
80 | " 2018 | \n",
81 | " 9 | \n",
82 | " 3 | \n",
83 | " 6 | \n",
84 | " 184 | \n",
85 | " 南信 算是 广州 著名 甜品店 吧 好几个 时间段 路过 都 是 座无虚席 看着 餐单 上 ... | \n",
86 | "
\n",
87 | " \n",
88 | " 1 | \n",
89 | " 稱霸幼稚園 | \n",
90 | " 2018-09-22 21:49:00 | \n",
91 | " sml-str40 | \n",
92 | " 中午 吃 完 了 所谓 的 早茶 回去 放下 行李 休息 了 会 就 来 吃 下午茶 了 服... | \n",
93 | " 很好 | \n",
94 | " 很好 | \n",
95 | " 很好 | \n",
96 | " 518986 | \n",
97 | " 4.0 | \n",
98 | " 2018 | \n",
99 | " 9 | \n",
100 | " 5 | \n",
101 | " 21 | \n",
102 | " 266 | \n",
103 | " 中午 吃 完 了 所谓 的 早茶 回去 放下 行李 休息 了 会 就 来 吃 下午茶 了 服... | \n",
104 | "
\n",
105 | " \n",
106 | " 2 | \n",
107 | " 爱吃的美美侠 | \n",
108 | " 2018-09-22 22:16:00 | \n",
109 | " sml-str40 | \n",
110 | " 冲刺 王者 战队 吃遍 蓉城 战队 有 特权 五月份 和 好 朋友 毕业 旅行 来 了 广州... | \n",
111 | " 很好 | \n",
112 | " 很好 | \n",
113 | " 很好 | \n",
114 | " 518986 | \n",
115 | " 4.0 | \n",
116 | " 2018 | \n",
117 | " 9 | \n",
118 | " 5 | \n",
119 | " 22 | \n",
120 | " 341 | \n",
121 | " 冲刺 王者 战队 吃遍 蓉城 战队 有 特权 五月份 和 好 朋友 毕业 旅行 来 了 广州... | \n",
122 | "
\n",
123 | " \n",
124 | " 3 | \n",
125 | " 姜姜会吃胖 | \n",
126 | " 2018-09-19 06:36:00 | \n",
127 | " sml-str40 | \n",
128 | " 都 说来 广州 吃 糖水 就要 来南信 招牌 姜撞奶 红豆 双皮奶 牛 三星 云吞面 一楼 ... | \n",
129 | " 非常好 | \n",
130 | " 很好 | \n",
131 | " 很好 | \n",
132 | " 518986 | \n",
133 | " 4.0 | \n",
134 | " 2018 | \n",
135 | " 9 | \n",
136 | " 2 | \n",
137 | " 6 | \n",
138 | " 197 | \n",
139 | " 都 说来 广州 吃 糖水 就要 来南信 招牌 姜撞奶 红豆 双皮奶 牛 三星 云吞面 一楼 ... | \n",
140 | "
\n",
141 | " \n",
142 | " 4 | \n",
143 | " forevercage | \n",
144 | " 2018-08-24 17:58:00 | \n",
145 | " sml-str50 | \n",
146 | " 一直 很 期待 也 最 爱 吃 甜品 广州 的 甜品 很 丰富 很 多样 来 之前 就 一直... | \n",
147 | " 非常好 | \n",
148 | " 很好 | \n",
149 | " 很好 | \n",
150 | " 518986 | \n",
151 | " 5.0 | \n",
152 | " 2018 | \n",
153 | " 8 | \n",
154 | " 4 | \n",
155 | " 17 | \n",
156 | " 261 | \n",
157 | " 一直 很 期待 也 最 爱 吃 甜品 广州 的 甜品 很 丰富 很 多样 来 之前 就 一直... | \n",
158 | "
\n",
159 | " \n",
160 | "
\n",
161 | "
"
162 | ],
163 | "text/plain": [
164 | " cus_id comment_time comment_star \\\n",
165 | "0 迷糊泰迪 2018-09-20 06:48:00 sml-str40 \n",
166 | "1 稱霸幼稚園 2018-09-22 21:49:00 sml-str40 \n",
167 | "2 爱吃的美美侠 2018-09-22 22:16:00 sml-str40 \n",
168 | "3 姜姜会吃胖 2018-09-19 06:36:00 sml-str40 \n",
169 | "4 forevercage 2018-08-24 17:58:00 sml-str50 \n",
170 | "\n",
171 | " cus_comment kouwei huanjing fuwu \\\n",
172 | "0 南信 算是 广州 著名 甜品店 吧 好几个 时间段 路过 都 是 座无虚席 看着 餐单 上 ... 非常好 好 好 \n",
173 | "1 中午 吃 完 了 所谓 的 早茶 回去 放下 行李 休息 了 会 就 来 吃 下午茶 了 服... 很好 很好 很好 \n",
174 | "2 冲刺 王者 战队 吃遍 蓉城 战队 有 特权 五月份 和 好 朋友 毕业 旅行 来 了 广州... 很好 很好 很好 \n",
175 | "3 都 说来 广州 吃 糖水 就要 来南信 招牌 姜撞奶 红豆 双皮奶 牛 三星 云吞面 一楼 ... 非常好 很好 很好 \n",
176 | "4 一直 很 期待 也 最 爱 吃 甜品 广州 的 甜品 很 丰富 很 多样 来 之前 就 一直... 非常好 很好 很好 \n",
177 | "\n",
178 | " shopID stars year month weekday hour comment_len \\\n",
179 | "0 518986 4.0 2018 9 3 6 184 \n",
180 | "1 518986 4.0 2018 9 5 21 266 \n",
181 | "2 518986 4.0 2018 9 5 22 341 \n",
182 | "3 518986 4.0 2018 9 2 6 197 \n",
183 | "4 518986 5.0 2018 8 4 17 261 \n",
184 | "\n",
185 | " cus_comment_processed \n",
186 | "0 南信 算是 广州 著名 甜品店 吧 好几个 时间段 路过 都 是 座无虚席 看着 餐单 上 ... \n",
187 | "1 中午 吃 完 了 所谓 的 早茶 回去 放下 行李 休息 了 会 就 来 吃 下午茶 了 服... \n",
188 | "2 冲刺 王者 战队 吃遍 蓉城 战队 有 特权 五月份 和 好 朋友 毕业 旅行 来 了 广州... \n",
189 | "3 都 说来 广州 吃 糖水 就要 来南信 招牌 姜撞奶 红豆 双皮奶 牛 三星 云吞面 一楼 ... \n",
190 | "4 一直 很 期待 也 最 爱 吃 甜品 广州 的 甜品 很 丰富 很 多样 来 之前 就 一直... "
191 | ]
192 | },
193 | "execution_count": 26,
194 | "metadata": {},
195 | "output_type": "execute_result"
196 | }
197 | ],
198 | "source": [
199 | "import pandas as pd\n",
200 | "from matplotlib import pyplot as plt\n",
201 | "import jieba\n",
202 | "data = pd.read_csv('data.csv')\n",
203 | "data.head()"
204 | ]
205 | },
206 | {
207 | "cell_type": "markdown",
208 | "metadata": {},
209 | "source": [
210 | "### 构建标签值\n",
211 | "\n",
212 | "大众点评的评分分为1-5分,1-2为差评,4-5为好评,3为中评,因此我们把1-2记为0,4-5记为1,3为中评,对我们的情感分析作用不大,丢弃掉这部分数据,但是可以作为训练语料模型的语料。我们的情感评分可以转化为标签值为1的概率值,这样我们就把情感分析问题转为文本分类问题了。"
213 | ]
214 | },
215 | {
216 | "cell_type": "code",
217 | "execution_count": 27,
218 | "metadata": {},
219 | "outputs": [],
220 | "source": [
221 | "#构建label值\n",
222 | "def zhuanhuan(score):\n",
223 | " if score > 3:\n",
224 | " return 1\n",
225 | " elif score < 3:\n",
226 | " return 0\n",
227 | " else:\n",
228 | " return None\n",
229 | " \n",
230 | "#特征值转换\n",
231 | "data['target'] = data['stars'].map(lambda x:zhuanhuan(x))\n",
232 | "data_model = data.dropna()"
233 | ]
234 | },
235 | {
236 | "cell_type": "markdown",
237 | "metadata": {},
238 | "source": [
239 | "### 文本特征处理\n",
240 | "\n",
241 | "中文文本特征处理,需要进行中文分词,jieba分词库简单好用。接下来需要过滤停用词,网上能够搜到现成的。最后就要进行文本转向量,有词库表示法、TF-IDF、word2vec等,这篇文章作了详细介绍,推荐一波 https://zhuanlan.zhihu.com/p/44917421\n",
242 | "\n",
243 | "这里我们使用sklearn库的TF-IDF工具进行文本特征提取。"
244 | ]
245 | },
246 | {
247 | "cell_type": "code",
248 | "execution_count": 48,
249 | "metadata": {},
250 | "outputs": [
251 | {
252 | "data": {
253 | "text/plain": [
254 | "26328 冲着 老字号 去 的 但 真的 不 咋 地 所有 的 东西 都 不是 先 做 的 点 了 煎...\n",
255 | "3457 名过其实 味道 一般 全是 人 价格 也 贵 感觉 碗碟 都 洗 不 干净\n",
256 | "17834 香芋 西米 以前 系 北京路 个边 上班 落 左班 都 会同 同事 去 吃糖 上个星期 去 ...\n",
257 | "7904 南信 的 双皮奶 非常 滑 不是 很甜 可是 很嫩 非常 美味 还有 鲜虾 肠有 好多好多 ...\n",
258 | "3258 环境 真的 是 一般 可能 是 老店 的 关系 但 很 传统 双皮奶 奶味重 甜度 适中 粥...\n",
259 | "Name: cus_comment, dtype: object"
260 | ]
261 | },
262 | "execution_count": 48,
263 | "metadata": {},
264 | "output_type": "execute_result"
265 | }
266 | ],
267 | "source": [
268 | "#切分测试集、训练集\n",
269 | "from sklearn.model_selection import train_test_split\n",
270 | "x_train, x_test, y_train, y_test = train_test_split(data_model['cus_comment'], data_model['target'], random_state=3, test_size=0.25)\n",
271 | "\n",
272 | "#引入停用词\n",
273 | "infile = open(\"stopwords.txt\",encoding='utf-8')\n",
274 | "stopwords_lst = infile.readlines()\n",
275 | "stopwords = [x.strip() for x in stopwords_lst]\n",
276 | "\n",
277 | "#中文分词\n",
278 | "def fenci(train_data):\n",
279 | " words_df = train_data.apply(lambda x:' '.join(jieba.cut(x)))\n",
280 | " return words_df\n",
281 | " \n",
282 | "x_train[:5]"
283 | ]
284 | },
285 | {
286 | "cell_type": "code",
287 | "execution_count": 49,
288 | "metadata": {},
289 | "outputs": [
290 | {
291 | "data": {
292 | "text/plain": [
293 | "TfidfVectorizer(analyzer='word', binary=False, decode_error='strict',\n",
294 | " dtype=, encoding='utf-8', input='content',\n",
295 | " lowercase=True, max_df=1.0, max_features=3000, min_df=1,\n",
296 | " ngram_range=(1, 2), norm='l2', preprocessor=None, smooth_idf=True,\n",
297 | " stop_words=['!', '\"', '#', '$', '%', '&', \"'\", '(', ')', '*', '+', ',', '-', '--', '.', '..', '...', '......', '...................', './', '.一', '记者', '数', '年', '月', '日', '时', '分', '秒', '/', '//', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '://', '::', ';', '<', '=', '>', '>>', '?', '@'...3', '94', '95', '96', '97', '98', '99', '100', '01', '02', '03', '04', '05', '06', '07', '08', '09'],\n",
298 | " strip_accents=None, sublinear_tf=False,\n",
299 | " token_pattern='(?u)\\\\b\\\\w\\\\w+\\\\b', tokenizer=None, use_idf=True,\n",
300 | " vocabulary=None)"
301 | ]
302 | },
303 | "execution_count": 49,
304 | "metadata": {},
305 | "output_type": "execute_result"
306 | }
307 | ],
308 | "source": [
309 | "#使用TF-IDF进行文本转向量处理\n",
310 | "from sklearn.feature_extraction.text import TfidfVectorizer\n",
311 | "tv = TfidfVectorizer(stop_words=stopwords, max_features=3000, ngram_range=(1,2))\n",
312 | "tv.fit(x_train)"
313 | ]
314 | },
315 | {
316 | "cell_type": "markdown",
317 | "metadata": {},
318 | "source": [
319 | "### 机器学习建模\n",
320 | "\n",
321 | "特征和标签已经准备好了,接下来就是建模了。这里我们使用文本分类的经典算法朴素贝叶斯算法,而且朴素贝叶斯算法的计算量较少。特征值是评论文本经过TF-IDF处理的向量,标签值评论的分类共两类,好评是1,差评是0。情感评分为分类器预测分类1的概率值。"
322 | ]
323 | },
324 | {
325 | "cell_type": "code",
326 | "execution_count": 50,
327 | "metadata": {},
328 | "outputs": [
329 | {
330 | "data": {
331 | "text/plain": [
332 | "0.9275308869629356"
333 | ]
334 | },
335 | "execution_count": 50,
336 | "metadata": {},
337 | "output_type": "execute_result"
338 | }
339 | ],
340 | "source": [
341 | "#计算分类效果的准确率\n",
342 | "from sklearn.naive_bayes import MultinomialNB\n",
343 | "from sklearn.metrics import roc_auc_score, f1_score\n",
344 | "classifier = MultinomialNB()\n",
345 | "classifier.fit(tv.transform(x_train), y_train)\n",
346 | "classifier.score(tv.transform(x_test), y_test)"
347 | ]
348 | },
349 | {
350 | "cell_type": "code",
351 | "execution_count": 51,
352 | "metadata": {
353 | "scrolled": false
354 | },
355 | "outputs": [
356 | {
357 | "data": {
358 | "text/plain": [
359 | "0.8971584233148908"
360 | ]
361 | },
362 | "execution_count": 51,
363 | "metadata": {},
364 | "output_type": "execute_result"
365 | }
366 | ],
367 | "source": [
368 | "#计算分类器的AUC值\n",
369 | "y_pred = classifier.predict_proba(tv.transform(x_test))[:,1]\n",
370 | "roc_auc_score(y_test,y_pred)"
371 | ]
372 | },
373 | {
374 | "cell_type": "code",
375 | "execution_count": 52,
376 | "metadata": {},
377 | "outputs": [],
378 | "source": [
379 | "#计算一条评论文本的情感评分\n",
380 | "def ceshi(model,strings):\n",
381 | " strings_fenci = fenci(pd.Series([strings]))\n",
382 | " return float(model.predict_proba(tv.transform(strings_fenci))[:,1])"
383 | ]
384 | },
385 | {
386 | "cell_type": "code",
387 | "execution_count": 53,
388 | "metadata": {},
389 | "outputs": [
390 | {
391 | "name": "stdout",
392 | "output_type": "stream",
393 | "text": [
394 | "好评实例的模型预测情感得分为0.8638082706675478\n",
395 | "差评实例的模型预测情感得分为0.7856544482460911\n"
396 | ]
397 | }
398 | ],
399 | "source": [
400 | "#从大众点评网找两条评论来测试一下\n",
401 | "test1 = '很好吃,环境好,所有员工的态度都很好,上菜快,服务也很好,味道好吃,都是用蒸馏水煮的,推荐,超好吃' #5星好评\n",
402 | "test2 = '糯米外皮不绵滑,豆沙馅粗躁,没有香甜味。12元一碗不值。' #1星差评\n",
403 | "print('好评实例的模型预测情感得分为{}\\n差评实例的模型预测情感得分为{}'.format(ceshi(classifier,test1),ceshi(classifier,test2)))"
404 | ]
405 | },
406 | {
407 | "cell_type": "markdown",
408 | "metadata": {},
409 | "source": [
410 | "可以看出,准确率和AUC值都非常不错的样子,但点评网上的实际测试中,5星好评模型预测出来了,1星差评缺预测错误。为什么呢?我们查看一下**混淆矩阵**"
411 | ]
412 | },
413 | {
414 | "cell_type": "code",
415 | "execution_count": 54,
416 | "metadata": {
417 | "scrolled": true
418 | },
419 | "outputs": [
420 | {
421 | "data": {
422 | "text/plain": [
423 | "array([[ 46, 385],\n",
424 | " [ 8, 4984]], dtype=int64)"
425 | ]
426 | },
427 | "execution_count": 54,
428 | "metadata": {},
429 | "output_type": "execute_result"
430 | }
431 | ],
432 | "source": [
433 | "from sklearn.metrics import confusion_matrix\n",
434 | "y_predict = classifier.predict(tv.transform(x_test))\n",
435 | "cm = confusion_matrix(y_test, y_predict)\n",
436 | "cm"
437 | ]
438 | },
439 | {
440 | "cell_type": "markdown",
441 | "metadata": {},
442 | "source": [
443 | "可以看出,**负类的预测非常不准**,433单准确预测为负类的只有15.7%,应该是由于**数据不平衡**导致的,模型的默认阈值为输出值的中位数。比如逻辑回归的输出范围为[0,1],当某个样本的输出大于0.5就会被划分为正例,反之为反例。在数据的类别不平衡时,采用默认的分类阈值可能会导致输出全部为正例,产生虚假的高准确度,导致分类失败。\n",
444 | "\n",
445 | "处理样本不均衡问题的方法,首先可以选择调整阈值,使得模型对于较少的类别更为敏感,或者选择合适的评估标准,比如ROC或者F1,而不是准确度(accuracy)。另外一种方法就是通过采样(sampling)来调整数据的不平衡。其中欠采样抛弃了大部分正例数据,从而弱化了其影响,可能会造成偏差很大的模型,同时,数据总是宝贵的,抛弃数据是很奢侈的。另外一种是过采样,下面我们就使用过采样方法来调整。\n",
446 | "\n",
447 | "### 过采样(单纯复制)\n",
448 | "\n",
449 | "单纯的重复了反例,因此会过分强调已有的反例。如果其中部分点标记错误或者是噪音,那么错误也容易被成倍的放大。因此最大的风险就是对反例过拟合。"
450 | ]
451 | },
452 | {
453 | "cell_type": "code",
454 | "execution_count": 55,
455 | "metadata": {
456 | "scrolled": true
457 | },
458 | "outputs": [
459 | {
460 | "data": {
461 | "text/plain": [
462 | "1.0 19916\n",
463 | "0.0 1779\n",
464 | "Name: target, dtype: int64"
465 | ]
466 | },
467 | "execution_count": 55,
468 | "metadata": {},
469 | "output_type": "execute_result"
470 | }
471 | ],
472 | "source": [
473 | "data['target'].value_counts()"
474 | ]
475 | },
476 | {
477 | "cell_type": "code",
478 | "execution_count": 56,
479 | "metadata": {},
480 | "outputs": [],
481 | "source": [
482 | "#把0类样本复制10次,构造训练集\n",
483 | "index_tmp = y_train==0\n",
484 | "y_tmp = y_train[index_tmp]\n",
485 | "x_tmp = x_train[index_tmp]\n",
486 | "x_train2 = pd.concat([x_train,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp])\n",
487 | "y_train2 = pd.concat([y_train,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp])"
488 | ]
489 | },
490 | {
491 | "cell_type": "code",
492 | "execution_count": 57,
493 | "metadata": {},
494 | "outputs": [
495 | {
496 | "data": {
497 | "text/plain": [
498 | "0.9049699937533463"
499 | ]
500 | },
501 | "execution_count": 57,
502 | "metadata": {},
503 | "output_type": "execute_result"
504 | }
505 | ],
506 | "source": [
507 | "#使用过采样样本(简单复制)进行模型训练,并查看准确率\n",
508 | "clf2 = MultinomialNB()\n",
509 | "clf2.fit(tv.transform(x_train2), y_train2)\n",
510 | "y_pred2 = clf2.predict_proba(tv.transform(x_test))[:,1]\n",
511 | "roc_auc_score(y_test,y_pred2)"
512 | ]
513 | },
514 | {
515 | "cell_type": "code",
516 | "execution_count": 58,
517 | "metadata": {
518 | "scrolled": true
519 | },
520 | "outputs": [
521 | {
522 | "data": {
523 | "text/plain": [
524 | "array([[ 331, 100],\n",
525 | " [ 637, 4355]], dtype=int64)"
526 | ]
527 | },
528 | "execution_count": 58,
529 | "metadata": {},
530 | "output_type": "execute_result"
531 | }
532 | ],
533 | "source": [
534 | "#查看此时的混淆矩阵\n",
535 | "y_predict2 = clf2.predict(tv.transform(x_test))\n",
536 | "cm = confusion_matrix(y_test, y_predict2)\n",
537 | "cm"
538 | ]
539 | },
540 | {
541 | "cell_type": "markdown",
542 | "metadata": {},
543 | "source": [
544 | "可以看出,即使是简单粗暴的复制样本来处理样本不平衡问题,负样本的识别率大幅上升了,变为77%,满满的幸福感呀~我们自己写两句评语来看看"
545 | ]
546 | },
547 | {
548 | "cell_type": "code",
549 | "execution_count": 59,
550 | "metadata": {
551 | "scrolled": false
552 | },
553 | "outputs": [
554 | {
555 | "data": {
556 | "text/plain": [
557 | "0.3520907656917545"
558 | ]
559 | },
560 | "execution_count": 59,
561 | "metadata": {},
562 | "output_type": "execute_result"
563 | }
564 | ],
565 | "source": [
566 | "ceshi(clf2,'排队人太多,环境不好,口味一般')"
567 | ]
568 | },
569 | {
570 | "cell_type": "markdown",
571 | "metadata": {},
572 | "source": [
573 | "可以看出把0类别的识别出来了,太棒了~"
574 | ]
575 | },
576 | {
577 | "cell_type": "markdown",
578 | "metadata": {},
579 | "source": [
580 | "### 过采样(SMOTE算法)\n",
581 | "\n",
582 | "SMOTE(Synthetic minoritye over-sampling technique,SMOTE),是在局部区域通过K-近邻生成了新的反例。相较于简单的过采样,SMOTE降低了过拟合风险,但同时运算开销加大\n",
583 | "\n",
584 | "对SMOTE感兴趣的同学可以看下这篇文章https://www.jianshu.com/p/ecbc924860af"
585 | ]
586 | },
587 | {
588 | "cell_type": "code",
589 | "execution_count": 60,
590 | "metadata": {},
591 | "outputs": [],
592 | "source": [
593 | "#使用SMOTE进行样本过采样处理\n",
594 | "from imblearn.over_sampling import SMOTE\n",
595 | "oversampler=SMOTE(random_state=0)\n",
596 | "x_train_vec = tv.transform(x_train)\n",
597 | "x_resampled, y_resampled = oversampler.fit_sample(x_train_vec, y_train)"
598 | ]
599 | },
600 | {
601 | "cell_type": "code",
602 | "execution_count": 61,
603 | "metadata": {},
604 | "outputs": [
605 | {
606 | "data": {
607 | "text/plain": [
608 | "1.0 14920\n",
609 | "0.0 1348\n",
610 | "Name: target, dtype: int64"
611 | ]
612 | },
613 | "execution_count": 61,
614 | "metadata": {},
615 | "output_type": "execute_result"
616 | }
617 | ],
618 | "source": [
619 | "#原始的样本分布\n",
620 | "y_train.value_counts()"
621 | ]
622 | },
623 | {
624 | "cell_type": "code",
625 | "execution_count": 62,
626 | "metadata": {
627 | "scrolled": true
628 | },
629 | "outputs": [
630 | {
631 | "data": {
632 | "text/plain": [
633 | "1.0 14920\n",
634 | "0.0 14920\n",
635 | "dtype: int64"
636 | ]
637 | },
638 | "execution_count": 62,
639 | "metadata": {},
640 | "output_type": "execute_result"
641 | }
642 | ],
643 | "source": [
644 | "#经过SMOTE算法过采样后的样本分布情况\n",
645 | "pd.Series(y_resampled).value_counts()"
646 | ]
647 | },
648 | {
649 | "cell_type": "markdown",
650 | "metadata": {},
651 | "source": [
652 | "我们经过插值,把0类数据也丰富为14923个数据了,这时候正负样本的比例为1:1,接下来我们用平衡后的数据进行训练,效果如何呢,好期待啊~"
653 | ]
654 | },
655 | {
656 | "cell_type": "code",
657 | "execution_count": 63,
658 | "metadata": {
659 | "scrolled": true
660 | },
661 | "outputs": [
662 | {
663 | "data": {
664 | "text/plain": [
665 | "0.9072990102028675"
666 | ]
667 | },
668 | "execution_count": 63,
669 | "metadata": {},
670 | "output_type": "execute_result"
671 | }
672 | ],
673 | "source": [
674 | "#使用过采样样本(SMOTE)进行模型训练,并查看准确率\n",
675 | "clf3 = MultinomialNB()\n",
676 | "clf3.fit(x_resampled, y_resampled)\n",
677 | "y_pred3 = clf3.predict_proba(tv.transform(x_test))[:,1]\n",
678 | "roc_auc_score(y_test,y_pred3)"
679 | ]
680 | },
681 | {
682 | "cell_type": "code",
683 | "execution_count": 64,
684 | "metadata": {
685 | "scrolled": false
686 | },
687 | "outputs": [
688 | {
689 | "data": {
690 | "text/plain": [
691 | "array([[ 330, 101],\n",
692 | " [ 601, 4391]], dtype=int64)"
693 | ]
694 | },
695 | "execution_count": 64,
696 | "metadata": {},
697 | "output_type": "execute_result"
698 | }
699 | ],
700 | "source": [
701 | "#查看此时的准确率\n",
702 | "y_predict3 = clf3.predict(tv.transform(x_test))\n",
703 | "cm = confusion_matrix(y_test, y_predict3)\n",
704 | "cm"
705 | ]
706 | },
707 | {
708 | "cell_type": "code",
709 | "execution_count": 65,
710 | "metadata": {
711 | "scrolled": true
712 | },
713 | "outputs": [
714 | {
715 | "data": {
716 | "text/plain": [
717 | "0.23491893934922978"
718 | ]
719 | },
720 | "execution_count": 65,
721 | "metadata": {},
722 | "output_type": "execute_result"
723 | }
724 | ],
725 | "source": [
726 | "#到网上找一条差评来测试一下情感评分的预测效果\n",
727 | "test3 = '糯米外皮不绵滑,豆沙馅粗躁,没有香甜味。12元一碗不值。'\n",
728 | "ceshi(clf3,test3)"
729 | ]
730 | },
731 | {
732 | "cell_type": "markdown",
733 | "metadata": {},
734 | "source": [
735 | "可以看出,使用SMOTE插值与简单的数据复制比起来,AUC率略有提高,实际预测效果也挺好\n",
736 | "\n",
737 | "### 模型评估测试\n",
738 | "\n",
739 | "接下来我们把3W条数据都拿来训练,数据量变多了,模型效果应该会更好"
740 | ]
741 | },
742 | {
743 | "cell_type": "code",
744 | "execution_count": 66,
745 | "metadata": {
746 | "scrolled": true
747 | },
748 | "outputs": [],
749 | "source": [
750 | "#词向量训练\n",
751 | "tv2 = TfidfVectorizer(stop_words=stopwords, max_features=3000, ngram_range=(1,2))\n",
752 | "tv2.fit(data_model['cus_comment'])\n",
753 | "\n",
754 | "#SMOTE插值\n",
755 | "X_tmp = tv2.transform(data_model['cus_comment'])\n",
756 | "y_tmp = data_model['target']\n",
757 | "sm = SMOTE(random_state=0)\n",
758 | "X,y = sm.fit_sample(X_tmp, y_tmp)\n",
759 | "\n",
760 | "clf = MultinomialNB()\n",
761 | "clf.fit(X, y)\n",
762 | "\n",
763 | "def fenxi(strings):\n",
764 | " strings_fenci = fenci(pd.Series([strings]))\n",
765 | " return float(clf.predict_proba(tv2.transform(strings_fenci))[:,1])"
766 | ]
767 | },
768 | {
769 | "cell_type": "code",
770 | "execution_count": 67,
771 | "metadata": {},
772 | "outputs": [
773 | {
774 | "data": {
775 | "text/plain": [
776 | "0.28900092243477077"
777 | ]
778 | },
779 | "execution_count": 67,
780 | "metadata": {},
781 | "output_type": "execute_result"
782 | }
783 | ],
784 | "source": [
785 | "#到网上找一条差评来测试一下\n",
786 | "fenxi('糯米外皮不绵滑,豆沙馅粗躁,没有香甜味。12元一碗不值。')"
787 | ]
788 | },
789 | {
790 | "cell_type": "markdown",
791 | "metadata": {},
792 | "source": [
793 | "只用到了简单的机器学习,就做出了不错的情感分析效果,知识的力量真是强大呀,666~\n",
794 | "### 后续优化方向\n",
795 | "\n",
796 | "- 使用更复杂的机器学习模型如神经网络、支持向量机等\n",
797 | "- 模型的调参\n",
798 | "- 行业词库的构建\n",
799 | "- 增加数据量\n",
800 | "- 优化情感分析的算法\n",
801 | "- 增加标签提取等\n",
802 | "- 项目部署到服务器上,更好地分享和测试模型的效果"
803 | ]
804 | }
805 | ],
806 | "metadata": {
807 | "kernelspec": {
808 | "display_name": "Python 3",
809 | "language": "python",
810 | "name": "python3"
811 | },
812 | "language_info": {
813 | "codemirror_mode": {
814 | "name": "ipython",
815 | "version": 3
816 | },
817 | "file_extension": ".py",
818 | "mimetype": "text/x-python",
819 | "name": "python",
820 | "nbconvert_exporter": "python",
821 | "pygments_lexer": "ipython3",
822 | "version": "3.6.5"
823 | }
824 | },
825 | "nbformat": 4,
826 | "nbformat_minor": 2
827 | }
828 |
--------------------------------------------------------------------------------
/文本分析挖掘/msyh.ttc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-bin/dianping_textmining/9abe0f28881bebc442b638c3606ccd7a3c803632/文本分析挖掘/msyh.ttc
--------------------------------------------------------------------------------
/文本分析挖掘/source/data_head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-bin/dianping_textmining/9abe0f28881bebc442b638c3606ccd7a3c803632/文本分析挖掘/source/data_head.png
--------------------------------------------------------------------------------
/文本分析挖掘/source/dianpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-bin/dianping_textmining/9abe0f28881bebc442b638c3606ccd7a3c803632/文本分析挖掘/source/dianpu.png
--------------------------------------------------------------------------------
/文本分析挖掘/source/len.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-bin/dianping_textmining/9abe0f28881bebc442b638c3606ccd7a3c803632/文本分析挖掘/source/len.png
--------------------------------------------------------------------------------
/文本分析挖掘/source/stars.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-bin/dianping_textmining/9abe0f28881bebc442b638c3606ccd7a3c803632/文本分析挖掘/source/stars.png
--------------------------------------------------------------------------------
/文本分析挖掘/source/time.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-bin/dianping_textmining/9abe0f28881bebc442b638c3606ccd7a3c803632/文本分析挖掘/source/time.png
--------------------------------------------------------------------------------
/文本分析挖掘/source/wordcloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/py-bin/dianping_textmining/9abe0f28881bebc442b638c3606ccd7a3c803632/文本分析挖掘/source/wordcloud.png
--------------------------------------------------------------------------------
/文本分析挖掘/stopwords.txt:
--------------------------------------------------------------------------------
1 | !
2 | "
3 | #
4 | $
5 | %
6 | &
7 | '
8 | (
9 | )
10 | *
11 | +
12 | ,
13 | -
14 | --
15 | .
16 | ..
17 | ...
18 | ......
19 | ...................
20 | ./
21 | .一
22 | 记者
23 | 数
24 | 年
25 | 月
26 | 日
27 | 时
28 | 分
29 | 秒
30 | /
31 | //
32 | 0
33 | 1
34 | 2
35 | 3
36 | 4
37 | 5
38 | 6
39 | 7
40 | 8
41 | 9
42 | :
43 | ://
44 | ::
45 | ;
46 | <
47 | =
48 | >
49 | >>
50 | ?
51 | @
52 | A
53 | Lex
54 | [
55 | \
56 | ]
57 | 【
58 | 】
59 | ^
60 | _
61 | `
62 | exp
63 | sub
64 | sup
65 | |
66 | }
67 | ~
68 | ~~~~
69 | ·
70 | ×
71 | ×××
72 | Δ
73 | Ψ
74 | γ
75 | μ
76 | φ
77 | φ.
78 | В
79 | —
80 | ——
81 | ———
82 | ‘
83 | ’
84 | ’‘
85 | “
86 | ”
87 | ”,
88 | …
89 | ……
90 | …………………………………………………③
91 | ′∈
92 | ′|
93 | ℃
94 | Ⅲ
95 | ↑
96 | →
97 | ∈[
98 | ∪φ∈
99 | ≈
100 | ①
101 | ②
102 | ②c
103 | ③
104 | ③]
105 | ④
106 | ⑤
107 | ⑥
108 | ⑦
109 | ⑧
110 | ⑨
111 | ⑩
112 | ──
113 | ■
114 | ▲
115 |
116 | 、
117 | 。
118 | 〈
119 | 〉
120 | 《
121 | 》
122 | 》),
123 | 」
124 | 『
125 | 』
126 | 〔
127 | 〕
128 | 〕〔
129 | ㈧
130 | 一
131 | 一.
132 | 一一
133 | 一下
134 | 一个
135 | 一些
136 | 一何
137 | 一切
138 | 一则
139 | 一则通过
140 | 一天
141 | 一定
142 | 一方面
143 | 一旦
144 | 一时
145 | 一来
146 | 一样
147 | 一次
148 | 一片
149 | 一番
150 | 一直
151 | 一致
152 | 一般
153 | 一起
154 | 一转眼
155 | 一边
156 | 一面
157 | 男子
158 | 女子
159 | 七
160 | 万一
161 | 三
162 | 三天两头
163 | 三番两次
164 | 三番五次
165 | 上
166 | 上下
167 | 上升
168 | 上去
169 | 上来
170 | 上述
171 | 上面
172 | 下
173 | 下列
174 | 下去
175 | 下来
176 | 下面
177 | 不
178 | 不一
179 | 不下
180 | 不久
181 | 不了
182 | 不亦乐乎
183 | 不仅
184 | 不仅...而且
185 | 不仅仅
186 | 不仅仅是
187 | 不会
188 | 不但
189 | 不但...而且
190 | 不光
191 | 不免
192 | 不再
193 | 不力
194 | 不单
195 | 不变
196 | 不只
197 | 不可
198 | 不可开交
199 | 不可抗拒
200 | 不同
201 | 不外
202 | 不外乎
203 | 不够
204 | 不大
205 | 不如
206 | 不妨
207 | 不定
208 | 不对
209 | 不少
210 | 不尽
211 | 不尽然
212 | 不巧
213 | 不已
214 | 不常
215 | 不得
216 | 不得不
217 | 不得了
218 | 不得已
219 | 不必
220 | 不怎么
221 | 不怕
222 | 不惟
223 | 不成
224 | 不拘
225 | 不择手段
226 | 不敢
227 | 不料
228 | 不断
229 | 不日
230 | 不时
231 | 不是
232 | 不曾
233 | 不止
234 | 不止一次
235 | 不比
236 | 不消
237 | 不满
238 | 不然
239 | 不然的话
240 | 不特
241 | 不独
242 | 不由得
243 | 不知不觉
244 | 不管
245 | 不管怎样
246 | 不经意
247 | 不胜
248 | 不能
249 | 不能不
250 | 不至于
251 | 不若
252 | 不要
253 | 不论
254 | 不起
255 | 不足
256 | 不过
257 | 不迭
258 | 不问
259 | 不限
260 | 与
261 | 与其
262 | 与其说
263 | 与否
264 | 与此同时
265 | 专门
266 | 且
267 | 且不说
268 | 且说
269 | 两者
270 | 严格
271 | 严重
272 | 个
273 | 个人
274 | 个别
275 | 中小
276 | 中间
277 | 丰富
278 | 串行
279 | 临
280 | 临到
281 | 为
282 | 为主
283 | 为了
284 | 为什么
285 | 为什麽
286 | 为何
287 | 为止
288 | 为此
289 | 为着
290 | 主张
291 | 主要
292 | 举凡
293 | 举行
294 | 乃
295 | 乃至
296 | 乃至于
297 | 么
298 | 之
299 | 之一
300 | 之前
301 | 之后
302 | 之後
303 | 之所以
304 | 之类
305 | 乌乎
306 | 乎
307 | 乒
308 | 乘
309 | 乘势
310 | 乘机
311 | 乘胜
312 | 乘虚
313 | 乘隙
314 | 九
315 | 也
316 | 也好
317 | 也就是说
318 | 也是
319 | 也罢
320 | 了
321 | 了解
322 | 争取
323 | 二
324 | 二来
325 | 二话不说
326 | 二话没说
327 | 于
328 | 于是
329 | 于是乎
330 | 云云
331 | 云尔
332 | 互
333 | 互相
334 | 五
335 | 些
336 | 交口
337 | 亦
338 | 产生
339 | 亲口
340 | 亲手
341 | 亲眼
342 | 亲自
343 | 亲身
344 | 人
345 | 人人
346 | 人们
347 | 人家
348 | 人民
349 | 什么
350 | 什么样
351 | 什麽
352 | 仅
353 | 仅仅
354 | 今
355 | 今后
356 | 今天
357 | 今年
358 | 今後
359 | 介于
360 | 仍
361 | 仍旧
362 | 仍然
363 | 从
364 | 从不
365 | 从严
366 | 从中
367 | 从事
368 | 从今以后
369 | 从优
370 | 从古到今
371 | 从古至今
372 | 从头
373 | 从宽
374 | 从小
375 | 从新
376 | 从无到有
377 | 从早到晚
378 | 从未
379 | 从来
380 | 从此
381 | 从此以后
382 | 从而
383 | 从轻
384 | 从速
385 | 从重
386 | 他
387 | 他人
388 | 他们
389 | 他是
390 | 他的
391 | 代替
392 | 以
393 | 以上
394 | 以下
395 | 以为
396 | 以便
397 | 以免
398 | 以前
399 | 以及
400 | 以后
401 | 以外
402 | 以後
403 | 以故
404 | 以期
405 | 以来
406 | 以至
407 | 以至于
408 | 以致
409 | 们
410 | 任
411 | 任何
412 | 任凭
413 | 任务
414 | 企图
415 | 伙同
416 | 会
417 | 伟大
418 | 传
419 | 传说
420 | 传闻
421 | 似乎
422 | 似的
423 | 但
424 | 但凡
425 | 但愿
426 | 但是
427 | 何
428 | 何乐而不为
429 | 何以
430 | 何况
431 | 何处
432 | 何妨
433 | 何尝
434 | 何必
435 | 何时
436 | 何止
437 | 何苦
438 | 何须
439 | 余外
440 | 作为
441 | 你
442 | 你们
443 | 你是
444 | 你的
445 | 使
446 | 使得
447 | 使用
448 | 例如
449 | 依
450 | 依据
451 | 依照
452 | 依靠
453 | 便
454 | 便于
455 | 促进
456 | 保持
457 | 保管
458 | 保险
459 | 俺
460 | 俺们
461 | 倍加
462 | 倍感
463 | 倒不如
464 | 倒不如说
465 | 倒是
466 | 倘
467 | 倘使
468 | 倘或
469 | 倘然
470 | 倘若
471 | 借
472 | 借以
473 | 借此
474 | 假使
475 | 假如
476 | 假若
477 | 偏偏
478 | 做到
479 | 偶尔
480 | 偶而
481 | 傥然
482 | 像
483 | 儿
484 | 允许
485 | 元/吨
486 | 充其极
487 | 充其量
488 | 充分
489 | 先不先
490 | 先后
491 | 先後
492 | 先生
493 | 光
494 | 光是
495 | 全体
496 | 全力
497 | 全年
498 | 全然
499 | 全身心
500 | 全部
501 | 全都
502 | 全面
503 | 八
504 | 八成
505 | 公然
506 | 六
507 | 兮
508 | 共
509 | 共同
510 | 共总
511 | 关于
512 | 其
513 | 其一
514 | 其中
515 | 其二
516 | 其他
517 | 其余
518 | 其后
519 | 其它
520 | 其实
521 | 其次
522 | 具体
523 | 具体地说
524 | 具体来说
525 | 具体说来
526 | 具有
527 | 兼之
528 | 内
529 | 再
530 | 再其次
531 | 再则
532 | 再有
533 | 再次
534 | 再者
535 | 再者说
536 | 再说
537 | 冒
538 | 冲
539 | 决不
540 | 决定
541 | 决非
542 | 况且
543 | 准备
544 | 凑巧
545 | 凝神
546 | 几
547 | 几乎
548 | 几度
549 | 几时
550 | 几番
551 | 几经
552 | 凡
553 | 凡是
554 | 凭
555 | 凭借
556 | 出
557 | 出于
558 | 出去
559 | 出来
560 | 出现
561 | 分别
562 | 分头
563 | 分期
564 | 分期分批
565 | 切
566 | 切不可
567 | 切切
568 | 切勿
569 | 切莫
570 | 则
571 | 则甚
572 | 刚
573 | 刚好
574 | 刚巧
575 | 刚才
576 | 初
577 | 别
578 | 别人
579 | 别处
580 | 别是
581 | 别的
582 | 别管
583 | 别说
584 | 到
585 | 到了儿
586 | 到处
587 | 到头
588 | 到头来
589 | 到底
590 | 到目前为止
591 | 前后
592 | 前此
593 | 前者
594 | 前进
595 | 前面
596 | 加上
597 | 加之
598 | 加以
599 | 加入
600 | 加强
601 | 动不动
602 | 动辄
603 | 勃然
604 | 匆匆
605 | 十分
606 | 千
607 | 千万
608 | 千万千万
609 | 半
610 | 单
611 | 单单
612 | 单纯
613 | 即
614 | 即令
615 | 即使
616 | 即便
617 | 即刻
618 | 即如
619 | 即将
620 | 即或
621 | 即是说
622 | 即若
623 | 却
624 | 却不
625 | 历
626 | 原来
627 | 去
628 | 又
629 | 又及
630 | 及
631 | 及其
632 | 及时
633 | 及至
634 | 双方
635 | 反之
636 | 反之亦然
637 | 反之则
638 | 反倒
639 | 反倒是
640 | 反应
641 | 反手
642 | 反映
643 | 反而
644 | 反过来
645 | 反过来说
646 | 取得
647 | 取道
648 | 受到
649 | 变成
650 | 古来
651 | 另
652 | 另一个
653 | 另一方面
654 | 另外
655 | 另悉
656 | 另方面
657 | 另行
658 | 只
659 | 只当
660 | 只怕
661 | 只是
662 | 只有
663 | 只消
664 | 只要
665 | 只限
666 | 叫
667 | 叫做
668 | 召开
669 | 叮咚
670 | 叮当
671 | 可
672 | 可以
673 | 可好
674 | 可是
675 | 可能
676 | 可见
677 | 各
678 | 各个
679 | 各人
680 | 各位
681 | 各地
682 | 各式
683 | 各种
684 | 各级
685 | 各自
686 | 合理
687 | 同
688 | 同一
689 | 同时
690 | 同样
691 | 后
692 | 后来
693 | 后者
694 | 后面
695 | 向
696 | 向使
697 | 向着
698 | 吓
699 | 吗
700 | 否则
701 | 吧
702 | 吧哒
703 | 吱
704 | 呀
705 | 呃
706 | 呆呆地
707 | 呐
708 | 呕
709 | 呗
710 | 呜
711 | 呜呼
712 | 呢
713 | 周围
714 | 呵
715 | 呵呵
716 | 呸
717 | 呼哧
718 | 呼啦
719 | 咋
720 | 和
721 | 咚
722 | 咦
723 | 咧
724 | 咱
725 | 咱们
726 | 咳
727 | 哇
728 | 哈
729 | 哈哈
730 | 哉
731 | 哎
732 | 哎呀
733 | 哎哟
734 | 哗
735 | 哗啦
736 | 哟
737 | 哦
738 | 哩
739 | 哪
740 | 哪个
741 | 哪些
742 | 哪儿
743 | 哪天
744 | 哪年
745 | 哪怕
746 | 哪样
747 | 哪边
748 | 哪里
749 | 哼
750 | 哼唷
751 | 唉
752 | 唯有
753 | 啊
754 | 啊呀
755 | 啊哈
756 | 啊哟
757 | 啐
758 | 啥
759 | 啦
760 | 啪达
761 | 啷当
762 | 喀
763 | 喂
764 | 喏
765 | 喔唷
766 | 喽
767 | 嗡
768 | 嗡嗡
769 | 嗬
770 | 嗯
771 | 嗳
772 | 嘎
773 | 嘎嘎
774 | 嘎登
775 | 嘘
776 | 嘛
777 | 嘻
778 | 嘿
779 | 嘿嘿
780 | 四
781 | 因
782 | 因为
783 | 因了
784 | 因此
785 | 因着
786 | 因而
787 | 固
788 | 固然
789 | 在
790 | 在下
791 | 在于
792 | 地
793 | 均
794 | 坚决
795 | 坚持
796 | 基于
797 | 基本
798 | 基本上
799 | 处在
800 | 处处
801 | 处理
802 | 复杂
803 | 多
804 | 多么
805 | 多亏
806 | 多多
807 | 多多少少
808 | 多多益善
809 | 多少
810 | 多年前
811 | 多年来
812 | 多数
813 | 多次
814 | 够瞧的
815 | 大
816 | 大不了
817 | 大举
818 | 大事
819 | 大体
820 | 大体上
821 | 大凡
822 | 大力
823 | 大多
824 | 大多数
825 | 大大
826 | 大家
827 | 大张旗鼓
828 | 大批
829 | 大抵
830 | 大概
831 | 大略
832 | 大约
833 | 大致
834 | 大都
835 | 大量
836 | 大面儿上
837 | 失去
838 | 奇
839 | 奈
840 | 奋勇
841 | 她
842 | 她们
843 | 她是
844 | 她的
845 | 好
846 | 好在
847 | 好的
848 | 好象
849 | 如
850 | 如上
851 | 如上所述
852 | 如下
853 | 如今
854 | 如何
855 | 如其
856 | 如前所述
857 | 如同
858 | 如常
859 | 如是
860 | 如期
861 | 如果
862 | 如次
863 | 如此
864 | 如此等等
865 | 如若
866 | 始而
867 | 姑且
868 | 存在
869 | 存心
870 | 孰料
871 | 孰知
872 | 宁
873 | 宁可
874 | 宁愿
875 | 宁肯
876 | 它
877 | 它们
878 | 它们的
879 | 它是
880 | 它的
881 | 安全
882 | 完全
883 | 完成
884 | 定
885 | 实现
886 | 实际
887 | 宣布
888 | 容易
889 | 密切
890 | 对
891 | 对于
892 | 对应
893 | 对待
894 | 对方
895 | 对比
896 | 将
897 | 将才
898 | 将要
899 | 将近
900 | 小
901 | 少数
902 | 尔
903 | 尔后
904 | 尔尔
905 | 尔等
906 | 尚且
907 | 尤其
908 | 就
909 | 就地
910 | 就是
911 | 就是了
912 | 就是说
913 | 就此
914 | 就算
915 | 就要
916 | 尽
917 | 尽可能
918 | 尽如人意
919 | 尽心尽力
920 | 尽心竭力
921 | 尽快
922 | 尽早
923 | 尽然
924 | 尽管
925 | 尽管如此
926 | 尽量
927 | 局外
928 | 居然
929 | 届时
930 | 属于
931 | 屡
932 | 屡屡
933 | 屡次
934 | 屡次三番
935 | 岂
936 | 岂但
937 | 岂止
938 | 岂非
939 | 川流不息
940 | 左右
941 | 巨大
942 | 巩固
943 | 差一点
944 | 差不多
945 | 己
946 | 已
947 | 已矣
948 | 已经
949 | 巴
950 | 巴巴
951 | 带
952 | 帮助
953 | 常
954 | 常常
955 | 常言说
956 | 常言说得好
957 | 常言道
958 | 平素
959 | 年复一年
960 | 并
961 | 并不
962 | 并不是
963 | 并且
964 | 并排
965 | 并无
966 | 并没
967 | 并没有
968 | 并肩
969 | 并非
970 | 广大
971 | 广泛
972 | 应当
973 | 应用
974 | 应该
975 | 庶乎
976 | 庶几
977 | 开外
978 | 开始
979 | 开展
980 | 引起
981 | 弗
982 | 弹指之间
983 | 强烈
984 | 强调
985 | 归
986 | 归根到底
987 | 归根结底
988 | 归齐
989 | 当
990 | 当下
991 | 当中
992 | 当儿
993 | 当前
994 | 当即
995 | 当口儿
996 | 当地
997 | 当场
998 | 当头
999 | 当庭
1000 | 当时
1001 | 当然
1002 | 当真
1003 | 当着
1004 | 形成
1005 | 彻夜
1006 | 彻底
1007 | 彼
1008 | 彼时
1009 | 彼此
1010 | 往
1011 | 往往
1012 | 待
1013 | 待到
1014 | 很
1015 | 很多
1016 | 很少
1017 | 後来
1018 | 後面
1019 | 得
1020 | 得了
1021 | 得出
1022 | 得到
1023 | 得天独厚
1024 | 得起
1025 | 心里
1026 | 必
1027 | 必定
1028 | 必将
1029 | 必然
1030 | 必要
1031 | 必须
1032 | 快
1033 | 快要
1034 | 忽地
1035 | 忽然
1036 | 怎
1037 | 怎么
1038 | 怎么办
1039 | 怎么样
1040 | 怎奈
1041 | 怎样
1042 | 怎麽
1043 | 怕
1044 | 急匆匆
1045 | 怪
1046 | 怪不得
1047 | 总之
1048 | 总是
1049 | 总的来看
1050 | 总的来说
1051 | 总的说来
1052 | 总结
1053 | 总而言之
1054 | 恍然
1055 | 恐怕
1056 | 恰似
1057 | 恰好
1058 | 恰如
1059 | 恰巧
1060 | 恰恰
1061 | 恰恰相反
1062 | 恰逢
1063 | 您
1064 | 您们
1065 | 您是
1066 | 惟其
1067 | 惯常
1068 | 意思
1069 | 愤然
1070 | 愿意
1071 | 慢说
1072 | 成为
1073 | 成年
1074 | 成年累月
1075 | 成心
1076 | 我
1077 | 我们
1078 | 我是
1079 | 我的
1080 | 或
1081 | 或则
1082 | 或多或少
1083 | 或是
1084 | 或曰
1085 | 或者
1086 | 或许
1087 | 战斗
1088 | 截然
1089 | 截至
1090 | 所
1091 | 所以
1092 | 所在
1093 | 所幸
1094 | 所有
1095 | 所谓
1096 | 才
1097 | 才能
1098 | 扑通
1099 | 打
1100 | 打从
1101 | 打开天窗说亮话
1102 | 扩大
1103 | 把
1104 | 抑或
1105 | 抽冷子
1106 | 拦腰
1107 | 拿
1108 | 按
1109 | 按时
1110 | 按期
1111 | 按照
1112 | 按理
1113 | 按说
1114 | 挨个
1115 | 挨家挨户
1116 | 挨次
1117 | 挨着
1118 | 挨门挨户
1119 | 挨门逐户
1120 | 换句话说
1121 | 换言之
1122 | 据
1123 | 据实
1124 | 据悉
1125 | 据我所知
1126 | 据此
1127 | 据称
1128 | 据说
1129 | 掌握
1130 | 接下来
1131 | 接着
1132 | 接著
1133 | 接连不断
1134 | 放量
1135 | 故
1136 | 故意
1137 | 故此
1138 | 故而
1139 | 敞开儿
1140 | 敢
1141 | 敢于
1142 | 敢情
1143 | 数/
1144 | 整个
1145 | 断然
1146 | 方
1147 | 方便
1148 | 方才
1149 | 方能
1150 | 方面
1151 | 旁人
1152 | 无
1153 | 无宁
1154 | 无法
1155 | 无论
1156 | 既
1157 | 既...又
1158 | 既往
1159 | 既是
1160 | 既然
1161 | 日复一日
1162 | 日渐
1163 | 日益
1164 | 日臻
1165 | 日见
1166 | 时候
1167 | 昂然
1168 | 明显
1169 | 明确
1170 | 是
1171 | 是不是
1172 | 是以
1173 | 是否
1174 | 是的
1175 | 显然
1176 | 显著
1177 | 普通
1178 | 普遍
1179 | 暗中
1180 | 暗地里
1181 | 暗自
1182 | 更
1183 | 更为
1184 | 更加
1185 | 更进一步
1186 | 曾
1187 | 曾经
1188 | 替
1189 | 替代
1190 | 最
1191 | 最后
1192 | 最大
1193 | 最好
1194 | 最後
1195 | 最近
1196 | 最高
1197 | 有
1198 | 有些
1199 | 有关
1200 | 有利
1201 | 有力
1202 | 有及
1203 | 有所
1204 | 有效
1205 | 有时
1206 | 有点
1207 | 有的
1208 | 有的是
1209 | 有着
1210 | 有著
1211 | 望
1212 | 朝
1213 | 朝着
1214 | 末##末
1215 | 本
1216 | 本人
1217 | 本地
1218 | 本着
1219 | 本身
1220 | 权时
1221 | 来
1222 | 来不及
1223 | 来得及
1224 | 来看
1225 | 来着
1226 | 来自
1227 | 来讲
1228 | 来说
1229 | 极
1230 | 极为
1231 | 极了
1232 | 极其
1233 | 极力
1234 | 极大
1235 | 极度
1236 | 极端
1237 | 构成
1238 | 果然
1239 | 果真
1240 | 某
1241 | 某个
1242 | 某些
1243 | 某某
1244 | 根据
1245 | 根本
1246 | 格外
1247 | 梆
1248 | 概
1249 | 次第
1250 | 欢迎
1251 | 欤
1252 | 正值
1253 | 正在
1254 | 正如
1255 | 正巧
1256 | 正常
1257 | 正是
1258 | 此
1259 | 此中
1260 | 此后
1261 | 此地
1262 | 此处
1263 | 此外
1264 | 此时
1265 | 此次
1266 | 此间
1267 | 殆
1268 | 毋宁
1269 | 每
1270 | 每个
1271 | 每天
1272 | 每年
1273 | 每当
1274 | 每时每刻
1275 | 每每
1276 | 每逢
1277 | 比
1278 | 比及
1279 | 比如
1280 | 比如说
1281 | 比方
1282 | 比照
1283 | 比起
1284 | 比较
1285 | 毕竟
1286 | 毫不
1287 | 毫无
1288 | 毫无例外
1289 | 毫无保留地
1290 | 汝
1291 | 沙沙
1292 | 没
1293 | 没奈何
1294 | 没有
1295 | 沿
1296 | 沿着
1297 | 注意
1298 | 活
1299 | 深入
1300 | 清楚
1301 | 满
1302 | 满足
1303 | 漫说
1304 | 焉
1305 | 然
1306 | 然则
1307 | 然后
1308 | 然後
1309 | 然而
1310 | 照
1311 | 照着
1312 | 牢牢
1313 | 特别是
1314 | 特殊
1315 | 特点
1316 | 犹且
1317 | 犹自
1318 | 独
1319 | 独自
1320 | 猛然
1321 | 猛然间
1322 | 率尔
1323 | 率然
1324 | 现代
1325 | 现在
1326 | 理应
1327 | 理当
1328 | 理该
1329 | 瑟瑟
1330 | 甚且
1331 | 甚么
1332 | 甚或
1333 | 甚而
1334 | 甚至
1335 | 甚至于
1336 | 用
1337 | 用来
1338 | 甫
1339 | 甭
1340 | 由
1341 | 由于
1342 | 由是
1343 | 由此
1344 | 由此可见
1345 | 略
1346 | 略为
1347 | 略加
1348 | 略微
1349 | 白
1350 | 白白
1351 | 的
1352 | 的确
1353 | 的话
1354 | 皆可
1355 | 目前
1356 | 直到
1357 | 直接
1358 | 相似
1359 | 相信
1360 | 相反
1361 | 相同
1362 | 相对
1363 | 相对而言
1364 | 相应
1365 | 相当
1366 | 相等
1367 | 省得
1368 | 看
1369 | 看上去
1370 | 看出
1371 | 看到
1372 | 看来
1373 | 看样子
1374 | 看看
1375 | 看见
1376 | 看起来
1377 | 真是
1378 | 真正
1379 | 眨眼
1380 | 着
1381 | 着呢
1382 | 矣
1383 | 矣乎
1384 | 矣哉
1385 | 知道
1386 | 砰
1387 | 确定
1388 | 碰巧
1389 | 社会主义
1390 | 离
1391 | 种
1392 | 积极
1393 | 移动
1394 | 究竟
1395 | 穷年累月
1396 | 突出
1397 | 突然
1398 | 窃
1399 | 立
1400 | 立刻
1401 | 立即
1402 | 立地
1403 | 立时
1404 | 立马
1405 | 竟
1406 | 竟然
1407 | 竟而
1408 | 第
1409 | 第二
1410 | 等
1411 | 等到
1412 | 等等
1413 | 策略地
1414 | 简直
1415 | 简而言之
1416 | 简言之
1417 | 管
1418 | 类如
1419 | 粗
1420 | 精光
1421 | 紧接着
1422 | 累年
1423 | 累次
1424 | 纯
1425 | 纯粹
1426 | 纵
1427 | 纵令
1428 | 纵使
1429 | 纵然
1430 | 练习
1431 | 组成
1432 | 经
1433 | 经常
1434 | 经过
1435 | 结合
1436 | 结果
1437 | 给
1438 | 绝
1439 | 绝不
1440 | 绝对
1441 | 绝非
1442 | 绝顶
1443 | 继之
1444 | 继后
1445 | 继续
1446 | 继而
1447 | 维持
1448 | 综上所述
1449 | 缕缕
1450 | 罢了
1451 | 老
1452 | 老大
1453 | 老是
1454 | 老老实实
1455 | 考虑
1456 | 者
1457 | 而
1458 | 而且
1459 | 而况
1460 | 而又
1461 | 而后
1462 | 而外
1463 | 而已
1464 | 而是
1465 | 而言
1466 | 而论
1467 | 联系
1468 | 联袂
1469 | 背地里
1470 | 背靠背
1471 | 能
1472 | 能否
1473 | 能够
1474 | 腾
1475 | 自
1476 | 自个儿
1477 | 自从
1478 | 自各儿
1479 | 自后
1480 | 自家
1481 | 自己
1482 | 自打
1483 | 自身
1484 | 臭
1485 | 至
1486 | 至于
1487 | 至今
1488 | 至若
1489 | 致
1490 | 般的
1491 | 良好
1492 | 若
1493 | 若夫
1494 | 若是
1495 | 若果
1496 | 若非
1497 | 范围
1498 | 莫
1499 | 莫不
1500 | 莫不然
1501 | 莫如
1502 | 莫若
1503 | 莫非
1504 | 获得
1505 | 藉以
1506 | 虽
1507 | 虽则
1508 | 虽然
1509 | 虽说
1510 | 蛮
1511 | 行为
1512 | 行动
1513 | 表明
1514 | 表示
1515 | 被
1516 | 要
1517 | 要不
1518 | 要不是
1519 | 要不然
1520 | 要么
1521 | 要是
1522 | 要求
1523 | 见
1524 | 规定
1525 | 觉得
1526 | 譬喻
1527 | 譬如
1528 | 认为
1529 | 认真
1530 | 认识
1531 | 让
1532 | 许多
1533 | 论
1534 | 论说
1535 | 设使
1536 | 设或
1537 | 设若
1538 | 诚如
1539 | 诚然
1540 | 话说
1541 | 该
1542 | 该当
1543 | 说明
1544 | 说来
1545 | 说说
1546 | 请勿
1547 | 诸
1548 | 诸位
1549 | 诸如
1550 | 谁
1551 | 谁人
1552 | 谁料
1553 | 谁知
1554 | 谨
1555 | 豁然
1556 | 贼死
1557 | 赖以
1558 | 赶
1559 | 赶快
1560 | 赶早不赶晚
1561 | 起
1562 | 起先
1563 | 起初
1564 | 起头
1565 | 起来
1566 | 起见
1567 | 起首
1568 | 趁
1569 | 趁便
1570 | 趁势
1571 | 趁早
1572 | 趁机
1573 | 趁热
1574 | 趁着
1575 | 越是
1576 | 距
1577 | 跟
1578 | 路经
1579 | 转动
1580 | 转变
1581 | 转贴
1582 | 轰然
1583 | 较
1584 | 较为
1585 | 较之
1586 | 较比
1587 | 边
1588 | 达到
1589 | 达旦
1590 | 迄
1591 | 迅速
1592 | 过
1593 | 过于
1594 | 过去
1595 | 过来
1596 | 运用
1597 | 近
1598 | 近几年来
1599 | 近年来
1600 | 近来
1601 | 还
1602 | 还是
1603 | 还有
1604 | 还要
1605 | 这
1606 | 这一来
1607 | 这个
1608 | 这么
1609 | 这么些
1610 | 这么样
1611 | 这么点儿
1612 | 这些
1613 | 这会儿
1614 | 这儿
1615 | 这就是说
1616 | 这时
1617 | 这样
1618 | 这次
1619 | 这点
1620 | 这种
1621 | 这般
1622 | 这边
1623 | 这里
1624 | 这麽
1625 | 进入
1626 | 进去
1627 | 进来
1628 | 进步
1629 | 进而
1630 | 进行
1631 | 连
1632 | 连同
1633 | 连声
1634 | 连日
1635 | 连日来
1636 | 连袂
1637 | 连连
1638 | 迟早
1639 | 迫于
1640 | 适应
1641 | 适当
1642 | 适用
1643 | 逐步
1644 | 逐渐
1645 | 通常
1646 | 通过
1647 | 造成
1648 | 逢
1649 | 遇到
1650 | 遭到
1651 | 遵循
1652 | 遵照
1653 | 避免
1654 | 那
1655 | 那个
1656 | 那么
1657 | 那么些
1658 | 那么样
1659 | 那些
1660 | 那会儿
1661 | 那儿
1662 | 那时
1663 | 那末
1664 | 那样
1665 | 那般
1666 | 那边
1667 | 那里
1668 | 那麽
1669 | 部分
1670 | 都
1671 | 鄙人
1672 | 采取
1673 | 里面
1674 | 重大
1675 | 重新
1676 | 重要
1677 | 鉴于
1678 | 针对
1679 | 长期以来
1680 | 长此下去
1681 | 长线
1682 | 长话短说
1683 | 问题
1684 | 间或
1685 | 防止
1686 | 阿
1687 | 附近
1688 | 陈年
1689 | 限制
1690 | 陡然
1691 | 除
1692 | 除了
1693 | 除却
1694 | 除去
1695 | 除外
1696 | 除开
1697 | 除此
1698 | 除此之外
1699 | 除此以外
1700 | 除此而外
1701 | 除非
1702 | 随
1703 | 随后
1704 | 随时
1705 | 随着
1706 | 随著
1707 | 隔夜
1708 | 隔日
1709 | 难得
1710 | 难怪
1711 | 难说
1712 | 难道
1713 | 难道说
1714 | 集中
1715 | 零
1716 | 需要
1717 | 非但
1718 | 非常
1719 | 非徒
1720 | 非得
1721 | 非特
1722 | 非独
1723 | 靠
1724 | 顶多
1725 | 顷
1726 | 顷刻
1727 | 顷刻之间
1728 | 顷刻间
1729 | 顺
1730 | 顺着
1731 | 顿时
1732 | 颇
1733 | 风雨无阻
1734 | 饱
1735 | 首先
1736 | 马上
1737 | 高低
1738 | 高兴
1739 | 默然
1740 | 默默地
1741 | 齐
1742 | ︿
1743 | !
1744 | #
1745 | $
1746 | %
1747 | &
1748 | '
1749 | (
1750 | )
1751 | )÷(1-
1752 | )、
1753 | *
1754 | +
1755 | +ξ
1756 | ++
1757 | ,
1758 | ,也
1759 | -
1760 | -β
1761 | --
1762 | -[*]-
1763 | .
1764 | /
1765 | 0
1766 | 0:2
1767 | 1
1768 | 1.
1769 | 12%
1770 | 2
1771 | 2.3%
1772 | 3
1773 | 4
1774 | 5
1775 | 5:0
1776 | 6
1777 | 7
1778 | 8
1779 | 9
1780 | :
1781 | ;
1782 | <
1783 | <±
1784 | <Δ
1785 | <λ
1786 | <φ
1787 | <<
1788 | =
1789 | =″
1790 | =☆
1791 | =(
1792 | =-
1793 | =[
1794 | ={
1795 | >
1796 | >λ
1797 | ?
1798 | @
1799 | A
1800 | LI
1801 | R.L.
1802 | ZXFITL
1803 |
1804 | [*]
1805 | [-
1806 | []
1807 | ]
1808 | ]∧′=[
1809 | ][
1810 | _
1811 | a]
1812 | b]
1813 | c]
1814 | e]
1815 | f]
1816 | ng昉
1817 | {
1818 | {-
1819 | |
1820 | }
1821 | }>
1822 | ~
1823 | ~±
1824 | ~+
1825 | ¥
1826 | secondly
1827 | all
1828 | whose
1829 | under
1830 | sorry
1831 | four
1832 | we'll
1833 | somewhere
1834 | likely
1835 | even
1836 | above
1837 | ever
1838 | never
1839 | ZZ
1840 | hers
1841 | i'd
1842 | howbeit
1843 | i'm
1844 | theres
1845 | changes
1846 | anyhow
1847 | would
1848 | therefore
1849 | is
1850 | hereby
1851 | must
1852 | me
1853 | my
1854 | indicated
1855 | indicates
1856 | keep
1857 | far
1858 | after
1859 | hereupon
1860 | keeps
1861 | every
1862 | over
1863 | before
1864 | better
1865 | then
1866 | them
1867 | they
1868 | reasonably
1869 | each
1870 | went
1871 | mean
1872 | we'd
1873 | rd
1874 | re
1875 | got
1876 | forth
1877 | you're
1878 | little
1879 | whereupon
1880 | uses
1881 | already
1882 | another
1883 | took
1884 | second
1885 | seen
1886 | seem
1887 | relatively
1888 | thoroughly
1889 | latter
1890 | that
1891 | thorough
1892 | nobody
1893 | definitely
1894 | came
1895 | saying
1896 | specify
1897 | do
1898 | next
1899 | despite
1900 | unfortunately
1901 | twice
1902 | best
1903 | said
1904 | away
1905 | there's
1906 | unto
1907 | hopefully
1908 | seven
1909 | we
1910 | ltd
1911 | here
1912 | against
1913 | com
1914 | ZT
1915 | aren't
1916 | been
1917 | much
1918 | concerning
1919 | wish
1920 | say
1921 | near
1922 | unlikely
1923 | cant
1924 | in
1925 | ie
1926 | if
1927 | containing
1928 | beside
1929 | several
1930 | kept
1931 | whereby
1932 | whoever
1933 | the
1934 | yours
1935 | just
1936 | yes
1937 | yet
1938 | had
1939 | has
1940 | t's
1941 | possible
1942 | apart
1943 | right
1944 | old
1945 | somehow
1946 | for
1947 | everything
1948 | asking
1949 | who
1950 | of
1951 | theirs
1952 | plus
1953 | formerly
1954 | down
1955 | c's
1956 | accordingly
1957 | way
1958 | was
1959 | becoming
1960 | tell
1961 | sometime
1962 | no
1963 | whereas
1964 | nd
1965 | welcome
1966 | let's
1967 | certainly
1968 | a's
1969 | did
1970 | it'll
1971 | says
1972 | appear
1973 | alone
1974 | wherever
1975 | example
1976 | usually
1977 | nowhere
1978 | hither
1979 | regardless
1980 | everybody
1981 | thru
1982 | everywhere
1983 | can
1984 | following
1985 | want
1986 | didn't
1987 | may
1988 | such
1989 | whenever
1990 | maybe
1991 | ones
1992 | so
1993 | seeing
1994 | indeed
1995 | course
1996 | still
1997 | thank
1998 | he's
1999 | selves
2000 | ours
2001 | outside
2002 | non
2003 | within
2004 | thereby
2005 | not
2006 | now
2007 | nor
2008 | entirely
2009 | eg
2010 | ex
2011 | et
2012 | hadn't
2013 | furthermore
2014 | looking
2015 | seriously
2016 | shouldn't
2017 | she
2018 | quite
2019 | besides
2020 | think
2021 | first
2022 | ignored
2023 | awfully
2024 | given
2025 | anyone
2026 | indicate
2027 | gives
2028 | mostly
2029 | than
2030 | here's
2031 | were
2032 | and
2033 | appreciate
2034 | himself
2035 | saw
2036 | any
2037 | downwards
2038 | take
2039 | sure
2040 | especially
2041 | later
2042 | that's
2043 | fifth
2044 | don't
2045 | aside
2046 | only
2047 | going
2048 | get
2049 | truly
2050 | cannot
2051 | nearly
2052 | regarding
2053 | us
2054 | where
2055 | up
2056 | namely
2057 | anyways
2058 | wonder
2059 | behind
2060 | between
2061 | it
2062 | across
2063 | come
2064 | many
2065 | whereafter
2066 | according
2067 | comes
2068 | afterwards
2069 | couldn't
2070 | moreover
2071 | considering
2072 | sensible
2073 | hardly
2074 | wants
2075 | former
2076 | those
2077 | these
2078 | [
2079 | somebody
2080 | different
2081 | etc
2082 | insofar
2083 | same
2084 | without
2085 | can't
2086 | very
2087 | you've
2088 | among
2089 | being
2090 | we've
2091 | seems
2092 | around
2093 | using
2094 | specified
2095 | on
2096 | ok
2097 | oh
2098 | whence
2099 | it's
2100 | or
2101 | everyone
2102 | your
2103 | her
2104 | there
2105 | amongst
2106 | trying
2107 | with
2108 | they're
2109 | wasn't
2110 | gone
2111 | certain
2112 | am
2113 | an
2114 | as
2115 | at
2116 | again
2117 | serious
2118 | hello
2119 | since
2120 | consider
2121 | causes
2122 | to
2123 | th
2124 | myself
2125 | i'll
2126 | zero
2127 | further
2128 | what
2129 | brief
2130 | seemed
2131 | c'mon
2132 | allows
2133 | followed
2134 | ask
2135 | viz
2136 | contains
2137 | two
2138 | taken
2139 | more
2140 | knows
2141 | ain't
2142 | particular
2143 | known
2144 | none
2145 | nine
2146 | needs
2147 | rather
2148 | [
2149 | okay
2150 | tried
2151 | tries
2152 | onto
2153 | perhaps
2154 | specifying
2155 | ]
2156 | help
2157 | soon
2158 | through
2159 | its
2160 | seeming
2161 | inward
2162 | actually
2163 | might
2164 | haven't
2165 | someone
2166 | hereafter
2167 | always
2168 | isn't
2169 | beyond
2170 | really
2171 | they'll
2172 | enough
2173 | thereafter
2174 | done
2175 | together
2176 | least
2177 | too
2178 | immediate
2179 | believe
2180 | gotten
2181 | toward
2182 | self
2183 | also
2184 | towards
2185 | most
2186 | nothing
2187 | they'd
2188 | sometimes
2189 | lest
2190 | particularly
2191 | somewhat
2192 | his
2193 | goes
2194 | meanwhile
2195 | during
2196 | him
2197 | greetings
2198 | see
2199 | are
2200 | currently
2201 | please
2202 | various
2203 | probably
2204 | available
2205 | both
2206 | last
2207 | wouldn't
2208 | became
2209 | whole
2210 | liked
2211 | whatever
2212 | except
2213 | throughout
2214 | along
2215 | described
2216 | though
2217 | whom
2218 | beforehand
2219 | what's
2220 | new
2221 | else
2222 | look
2223 | while
2224 | herein
2225 | itself
2226 | wherein
2227 | used
2228 | anybody
2229 | obviously
2230 | thats
2231 | from
2232 | useful
2233 | merely
2234 | follows
2235 | often
2236 | some
2237 | ourselves
2238 | shall
2239 | per
2240 | tends
2241 | either
2242 | be
2243 | by
2244 | anything
2245 | consequently
2246 | into
2247 | appropriate
2248 | we're
2249 | elsewhere
2250 | hasn't
2251 | un
2252 | noone
2253 | associated
2254 | thanks
2255 | having
2256 | once
2257 | edu
2258 | go
2259 | sent
2260 | provides
2261 | yourselves
2262 | they've
2263 | try
2264 | this
2265 | you'd
2266 | yourself
2267 | zz
2268 | zt
2269 | respectively
2270 | let
2271 | others
2272 | until
2273 | weren't
2274 | use
2275 | few
2276 | themselves
2277 | becomes
2278 | anywhere
2279 | something
2280 | six
2281 | allow
2282 | won't
2283 | thence
2284 | willing
2285 | instead
2286 | whither
2287 | doing
2288 | how
2289 | cause
2290 | thereupon
2291 | que
2292 | via
2293 | could
2294 | hence
2295 | third
2296 | doesn't
2297 | their
2298 | exactly
2299 | regards
2300 | herself
2301 | have
2302 | need
2303 | clearly
2304 | i've
2305 | able
2306 | which
2307 | unless
2308 | where's
2309 | eight
2310 | why
2311 | you'll
2312 | normally
2313 | anyway
2314 | one
2315 | should
2316 | mainly
2317 | overall
2318 | qv
2319 | contain
2320 | looks
2321 | neither
2322 | however
2323 | otherwise
2324 | co
2325 | it'd
2326 | corresponding
2327 | thanx
2328 | novel
2329 | value
2330 | will
2331 | almost
2332 | thus
2333 | vs
2334 | when
2335 | gets
2336 | upon
2337 | off
2338 | nevertheless
2339 | well
2340 | less
2341 | presumably
2342 | ought
2343 | who's
2344 | five
2345 | know
2346 | you
2347 | name
2348 | necessary
2349 | like
2350 | become
2351 | therein
2352 | because
2353 | happens
2354 | does
2355 | although
2356 | about
2357 | getting
2358 | own
2359 | three
2360 | inasmuch
2361 | inner
2362 | but
2363 | hi
2364 | he
2365 | whether
2366 | placed
2367 | below
2368 | our
2369 | 上去--
2370 | inc
2371 | lately
2372 | other
2373 | latterly
2374 | out
2375 | 是什么
2376 | 什么时候
2377 | 是什么意思
2378 | 什么意思
2379 | 多少钱
2380 | 有没有
2381 | 更有趣
2382 | 更有甚者
2383 | 更有效
2384 | 更有意义
2385 | 更远的
2386 | 更重要的是
2387 | 正确
2388 | 错误
2389 | 第二把
2390 | 第二波
2391 | 第二大节
2392 | 第二单元
2393 | 第二关
2394 | 第二行
2395 | 第二集
2396 | 第二讲
2397 | 第二款
2398 | 第二类
2399 | 第二盘
2400 | 第二任
2401 | 第二声
2402 | 第二十
2403 | 第二首
2404 | 第二项
2405 | 第三遍
2406 | 第三册
2407 | 第三层
2408 | 第三产业
2409 | 第三大
2410 | 第三单元
2411 | 第三行
2412 | 第三回
2413 | 第三集
2414 | 第三件
2415 | 第三句
2416 | 第三卷
2417 | 第三课
2418 | 第三类
2419 | 第三篇
2420 | 第三期
2421 | 第三日
2422 | 第三声
2423 | 地三鲜
2424 | 第三项
2425 | 第三站
2426 | 第三张
2427 | 第十八
2428 | 第十次
2429 | 第十二
2430 | 的士高
2431 | 第十集
2432 | 第十届
2433 | 第十九
2434 | 第十六
2435 | 第十名
2436 | 第十三
2437 | 第十四
2438 | 第十天
2439 | 第十一
2440 | 第十一个
2441 | 第四版
2442 | 第四册
2443 | 第四场
2444 | 第四代
2445 | 第四单元
2446 | 第四集
2447 | 第四届
2448 | 第四年
2449 | 第四期
2450 | 第四声
2451 | 第四套
2452 | 第四位
2453 | 第四张
2454 | 第四者
2455 | 第四种
2456 | 第五部
2457 | 第五大道
2458 | 第五单元
2459 | 第五集
2460 | 第五卷
2461 | 第五课
2462 | 第五年
2463 | 第五期
2464 | 第五位
2465 | 第五元素
2466 | 第五组
2467 | 召唤
2468 | 最后一班
2469 | 最后一遍
2470 | 最后一关
2471 | 最后一集
2472 | 最后一科
2473 | 最后一颗子弹
2474 | 最后一派
2475 | 最后一题
2476 | 最后一眼
2477 | 最后一页
2478 | 10
2479 | 11
2480 | 12
2481 | 35
2482 | 25
2483 | 2016
2484 | 2015
2485 | 2014
2486 | 又为什么
2487 | 有问题吗
2488 | 有问题么
2489 | 又喜欢
2490 | 有喜欢
2491 | 又小
2492 | 又笑
2493 | 有笑
2494 | 有效地
2495 | 有一百
2496 | 又一遍
2497 | 有一部
2498 | 又一城
2499 | 又一村
2500 | 有一道
2501 | 有意的
2502 | 有一堆
2503 | 有一对
2504 | 有一方
2505 | 有一根
2506 | 有一会了
2507 | 有一批
2508 | 有一片
2509 | 有一期
2510 | 有一起
2511 | 有一群
2512 | 又又
2513 | 由由
2514 | 财新网
2515 | 上午
2516 | 下午
2517 | NULL
2518 | 新华社
2519 | 消息
2520 | 13
2521 | 14
2522 | 15
2523 | 16
2524 | 17
2525 | 18
2526 | 19
2527 | 20
2528 | 21
2529 | 22
2530 | 23
2531 | 24
2532 | 26
2533 | 27
2534 | 28
2535 | 29
2536 | 30
2537 | 31
2538 | 32
2539 | 33
2540 | 34
2541 | 36
2542 | 37
2543 | 38
2544 | 39
2545 | 40
2546 | 41
2547 | 42
2548 | 43
2549 | 44
2550 | 45
2551 | 46
2552 | 47
2553 | 48
2554 | 49
2555 | 50
2556 | 51
2557 | 52
2558 | 53
2559 | 54
2560 | 55
2561 | 56
2562 | 57
2563 | 58
2564 | 59
2565 | 60
2566 | 61
2567 | 62
2568 | 63
2569 | 64
2570 | 65
2571 | 66
2572 | 67
2573 | 68
2574 | 69
2575 | 70
2576 | 71
2577 | 72
2578 | 73
2579 | 74
2580 | 75
2581 | 76
2582 | 77
2583 | 78
2584 | 79
2585 | 80
2586 | 81
2587 | 82
2588 | 83
2589 | 84
2590 | 85
2591 | 86
2592 | 87
2593 | 88
2594 | 89
2595 | 90
2596 | 91
2597 | 92
2598 | 93
2599 | 94
2600 | 95
2601 | 96
2602 | 97
2603 | 98
2604 | 99
2605 | 100
2606 | 01
2607 | 02
2608 | 03
2609 | 04
2610 | 05
2611 | 06
2612 | 07
2613 | 08
2614 | 09
2615 |
--------------------------------------------------------------------------------
/文本分析挖掘/文本挖掘&情感分析.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# 大众点评评价情感分析~\n",
8 | "先上结果:\n",
9 | "\n",
10 | "| 糖水店的评论文本 | 模型预测的情感评分 |\n",
11 | "| :------------------------------------------- | :----------------- |\n",
12 | "| '糖水味道不错,滑而不腻,赞一个,下次还会来' | 0.91 |\n",
13 | "| '味道一般,没啥特点' | 0.52 |\n",
14 | "| '排队老半天,环境很差,味道一般般' | 0.05 |\n",
15 | "\n",
16 | "模型的效果还可以的样子,yeah~接下来我们好好讲讲怎么做的哈,我们通过爬虫爬取了大众点评广州8家最热门糖水店的3W条评论信息以及评分作为训练数据,前面的分析我们得知*样本很不均衡*。接下来我们的整体思路就是:文本特征处理(分词、去停用词、TF-IDF)—机器学习建模—模型评价。\n",
17 | "\n",
18 | "我们先不处理样本不均衡问题,直接建模后查看结果,接下来我们再按照两种方法处理样本不均衡,对比结果。\n",
19 | "\n",
20 | "### 数据读入和探索"
21 | ]
22 | },
23 | {
24 | "cell_type": "code",
25 | "execution_count": 26,
26 | "metadata": {
27 | "scrolled": true
28 | },
29 | "outputs": [
30 | {
31 | "data": {
32 | "text/html": [
33 | "\n",
34 | "\n",
47 | "
\n",
48 | " \n",
49 | " \n",
50 | " | \n",
51 | " cus_id | \n",
52 | " comment_time | \n",
53 | " comment_star | \n",
54 | " cus_comment | \n",
55 | " kouwei | \n",
56 | " huanjing | \n",
57 | " fuwu | \n",
58 | " shopID | \n",
59 | " stars | \n",
60 | " year | \n",
61 | " month | \n",
62 | " weekday | \n",
63 | " hour | \n",
64 | " comment_len | \n",
65 | " cus_comment_processed | \n",
66 | "
\n",
67 | " \n",
68 | " \n",
69 | " \n",
70 | " 0 | \n",
71 | " 迷糊泰迪 | \n",
72 | " 2018-09-20 06:48:00 | \n",
73 | " sml-str40 | \n",
74 | " 南信 算是 广州 著名 甜品店 吧 好几个 时间段 路过 都 是 座无虚席 看着 餐单 上 ... | \n",
75 | " 非常好 | \n",
76 | " 好 | \n",
77 | " 好 | \n",
78 | " 518986 | \n",
79 | " 4.0 | \n",
80 | " 2018 | \n",
81 | " 9 | \n",
82 | " 3 | \n",
83 | " 6 | \n",
84 | " 184 | \n",
85 | " 南信 算是 广州 著名 甜品店 吧 好几个 时间段 路过 都 是 座无虚席 看着 餐单 上 ... | \n",
86 | "
\n",
87 | " \n",
88 | " 1 | \n",
89 | " 稱霸幼稚園 | \n",
90 | " 2018-09-22 21:49:00 | \n",
91 | " sml-str40 | \n",
92 | " 中午 吃 完 了 所谓 的 早茶 回去 放下 行李 休息 了 会 就 来 吃 下午茶 了 服... | \n",
93 | " 很好 | \n",
94 | " 很好 | \n",
95 | " 很好 | \n",
96 | " 518986 | \n",
97 | " 4.0 | \n",
98 | " 2018 | \n",
99 | " 9 | \n",
100 | " 5 | \n",
101 | " 21 | \n",
102 | " 266 | \n",
103 | " 中午 吃 完 了 所谓 的 早茶 回去 放下 行李 休息 了 会 就 来 吃 下午茶 了 服... | \n",
104 | "
\n",
105 | " \n",
106 | " 2 | \n",
107 | " 爱吃的美美侠 | \n",
108 | " 2018-09-22 22:16:00 | \n",
109 | " sml-str40 | \n",
110 | " 冲刺 王者 战队 吃遍 蓉城 战队 有 特权 五月份 和 好 朋友 毕业 旅行 来 了 广州... | \n",
111 | " 很好 | \n",
112 | " 很好 | \n",
113 | " 很好 | \n",
114 | " 518986 | \n",
115 | " 4.0 | \n",
116 | " 2018 | \n",
117 | " 9 | \n",
118 | " 5 | \n",
119 | " 22 | \n",
120 | " 341 | \n",
121 | " 冲刺 王者 战队 吃遍 蓉城 战队 有 特权 五月份 和 好 朋友 毕业 旅行 来 了 广州... | \n",
122 | "
\n",
123 | " \n",
124 | " 3 | \n",
125 | " 姜姜会吃胖 | \n",
126 | " 2018-09-19 06:36:00 | \n",
127 | " sml-str40 | \n",
128 | " 都 说来 广州 吃 糖水 就要 来南信 招牌 姜撞奶 红豆 双皮奶 牛 三星 云吞面 一楼 ... | \n",
129 | " 非常好 | \n",
130 | " 很好 | \n",
131 | " 很好 | \n",
132 | " 518986 | \n",
133 | " 4.0 | \n",
134 | " 2018 | \n",
135 | " 9 | \n",
136 | " 2 | \n",
137 | " 6 | \n",
138 | " 197 | \n",
139 | " 都 说来 广州 吃 糖水 就要 来南信 招牌 姜撞奶 红豆 双皮奶 牛 三星 云吞面 一楼 ... | \n",
140 | "
\n",
141 | " \n",
142 | " 4 | \n",
143 | " forevercage | \n",
144 | " 2018-08-24 17:58:00 | \n",
145 | " sml-str50 | \n",
146 | " 一直 很 期待 也 最 爱 吃 甜品 广州 的 甜品 很 丰富 很 多样 来 之前 就 一直... | \n",
147 | " 非常好 | \n",
148 | " 很好 | \n",
149 | " 很好 | \n",
150 | " 518986 | \n",
151 | " 5.0 | \n",
152 | " 2018 | \n",
153 | " 8 | \n",
154 | " 4 | \n",
155 | " 17 | \n",
156 | " 261 | \n",
157 | " 一直 很 期待 也 最 爱 吃 甜品 广州 的 甜品 很 丰富 很 多样 来 之前 就 一直... | \n",
158 | "
\n",
159 | " \n",
160 | "
\n",
161 | "
"
162 | ],
163 | "text/plain": [
164 | " cus_id comment_time comment_star \\\n",
165 | "0 迷糊泰迪 2018-09-20 06:48:00 sml-str40 \n",
166 | "1 稱霸幼稚園 2018-09-22 21:49:00 sml-str40 \n",
167 | "2 爱吃的美美侠 2018-09-22 22:16:00 sml-str40 \n",
168 | "3 姜姜会吃胖 2018-09-19 06:36:00 sml-str40 \n",
169 | "4 forevercage 2018-08-24 17:58:00 sml-str50 \n",
170 | "\n",
171 | " cus_comment kouwei huanjing fuwu \\\n",
172 | "0 南信 算是 广州 著名 甜品店 吧 好几个 时间段 路过 都 是 座无虚席 看着 餐单 上 ... 非常好 好 好 \n",
173 | "1 中午 吃 完 了 所谓 的 早茶 回去 放下 行李 休息 了 会 就 来 吃 下午茶 了 服... 很好 很好 很好 \n",
174 | "2 冲刺 王者 战队 吃遍 蓉城 战队 有 特权 五月份 和 好 朋友 毕业 旅行 来 了 广州... 很好 很好 很好 \n",
175 | "3 都 说来 广州 吃 糖水 就要 来南信 招牌 姜撞奶 红豆 双皮奶 牛 三星 云吞面 一楼 ... 非常好 很好 很好 \n",
176 | "4 一直 很 期待 也 最 爱 吃 甜品 广州 的 甜品 很 丰富 很 多样 来 之前 就 一直... 非常好 很好 很好 \n",
177 | "\n",
178 | " shopID stars year month weekday hour comment_len \\\n",
179 | "0 518986 4.0 2018 9 3 6 184 \n",
180 | "1 518986 4.0 2018 9 5 21 266 \n",
181 | "2 518986 4.0 2018 9 5 22 341 \n",
182 | "3 518986 4.0 2018 9 2 6 197 \n",
183 | "4 518986 5.0 2018 8 4 17 261 \n",
184 | "\n",
185 | " cus_comment_processed \n",
186 | "0 南信 算是 广州 著名 甜品店 吧 好几个 时间段 路过 都 是 座无虚席 看着 餐单 上 ... \n",
187 | "1 中午 吃 完 了 所谓 的 早茶 回去 放下 行李 休息 了 会 就 来 吃 下午茶 了 服... \n",
188 | "2 冲刺 王者 战队 吃遍 蓉城 战队 有 特权 五月份 和 好 朋友 毕业 旅行 来 了 广州... \n",
189 | "3 都 说来 广州 吃 糖水 就要 来南信 招牌 姜撞奶 红豆 双皮奶 牛 三星 云吞面 一楼 ... \n",
190 | "4 一直 很 期待 也 最 爱 吃 甜品 广州 的 甜品 很 丰富 很 多样 来 之前 就 一直... "
191 | ]
192 | },
193 | "execution_count": 26,
194 | "metadata": {},
195 | "output_type": "execute_result"
196 | }
197 | ],
198 | "source": [
199 | "import pandas as pd\n",
200 | "from matplotlib import pyplot as plt\n",
201 | "import jieba\n",
202 | "data = pd.read_csv('data.csv')\n",
203 | "data.head()"
204 | ]
205 | },
206 | {
207 | "cell_type": "markdown",
208 | "metadata": {},
209 | "source": [
210 | "### 构建标签值\n",
211 | "\n",
212 | "大众点评的评分分为1-5分,1-2为差评,4-5为好评,3为中评,因此我们把1-2记为0,4-5记为1,3为中评,对我们的情感分析作用不大,丢弃掉这部分数据,但是可以作为训练语料模型的语料。我们的情感评分可以转化为标签值为1的概率值,这样我们就把情感分析问题转为文本分类问题了。"
213 | ]
214 | },
215 | {
216 | "cell_type": "code",
217 | "execution_count": 27,
218 | "metadata": {},
219 | "outputs": [],
220 | "source": [
221 | "#构建label值\n",
222 | "def zhuanhuan(score):\n",
223 | " if score > 3:\n",
224 | " return 1\n",
225 | " elif score < 3:\n",
226 | " return 0\n",
227 | " else:\n",
228 | " return None\n",
229 | " \n",
230 | "#特征值转换\n",
231 | "data['target'] = data['stars'].map(lambda x:zhuanhuan(x))\n",
232 | "data_model = data.dropna()"
233 | ]
234 | },
235 | {
236 | "cell_type": "markdown",
237 | "metadata": {},
238 | "source": [
239 | "### 文本特征处理\n",
240 | "\n",
241 | "中文文本特征处理,需要进行中文分词,jieba分词库简单好用。接下来需要过滤停用词,网上能够搜到现成的。最后就要进行文本转向量,有词库表示法、TF-IDF、word2vec等,这篇文章作了详细介绍,推荐一波 https://zhuanlan.zhihu.com/p/44917421\n",
242 | "\n",
243 | "这里我们使用sklearn库的TF-IDF工具进行文本特征提取。"
244 | ]
245 | },
246 | {
247 | "cell_type": "code",
248 | "execution_count": 48,
249 | "metadata": {},
250 | "outputs": [
251 | {
252 | "data": {
253 | "text/plain": [
254 | "26328 冲着 老字号 去 的 但 真的 不 咋 地 所有 的 东西 都 不是 先 做 的 点 了 煎...\n",
255 | "3457 名过其实 味道 一般 全是 人 价格 也 贵 感觉 碗碟 都 洗 不 干净\n",
256 | "17834 香芋 西米 以前 系 北京路 个边 上班 落 左班 都 会同 同事 去 吃糖 上个星期 去 ...\n",
257 | "7904 南信 的 双皮奶 非常 滑 不是 很甜 可是 很嫩 非常 美味 还有 鲜虾 肠有 好多好多 ...\n",
258 | "3258 环境 真的 是 一般 可能 是 老店 的 关系 但 很 传统 双皮奶 奶味重 甜度 适中 粥...\n",
259 | "Name: cus_comment, dtype: object"
260 | ]
261 | },
262 | "execution_count": 48,
263 | "metadata": {},
264 | "output_type": "execute_result"
265 | }
266 | ],
267 | "source": [
268 | "#切分测试集、训练集\n",
269 | "from sklearn.model_selection import train_test_split\n",
270 | "x_train, x_test, y_train, y_test = train_test_split(data_model['cus_comment'], data_model['target'], random_state=3, test_size=0.25)\n",
271 | "\n",
272 | "#引入停用词\n",
273 | "infile = open(\"stopwords.txt\",encoding='utf-8')\n",
274 | "stopwords_lst = infile.readlines()\n",
275 | "stopwords = [x.strip() for x in stopwords_lst]\n",
276 | "\n",
277 | "#中文分词\n",
278 | "def fenci(train_data):\n",
279 | " words_df = train_data.apply(lambda x:' '.join(jieba.cut(x)))\n",
280 | " return words_df\n",
281 | " \n",
282 | "x_train[:5]"
283 | ]
284 | },
285 | {
286 | "cell_type": "code",
287 | "execution_count": 49,
288 | "metadata": {},
289 | "outputs": [
290 | {
291 | "data": {
292 | "text/plain": [
293 | "TfidfVectorizer(analyzer='word', binary=False, decode_error='strict',\n",
294 | " dtype=, encoding='utf-8', input='content',\n",
295 | " lowercase=True, max_df=1.0, max_features=3000, min_df=1,\n",
296 | " ngram_range=(1, 2), norm='l2', preprocessor=None, smooth_idf=True,\n",
297 | " stop_words=['!', '\"', '#', '$', '%', '&', \"'\", '(', ')', '*', '+', ',', '-', '--', '.', '..', '...', '......', '...................', './', '.一', '记者', '数', '年', '月', '日', '时', '分', '秒', '/', '//', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '://', '::', ';', '<', '=', '>', '>>', '?', '@'...3', '94', '95', '96', '97', '98', '99', '100', '01', '02', '03', '04', '05', '06', '07', '08', '09'],\n",
298 | " strip_accents=None, sublinear_tf=False,\n",
299 | " token_pattern='(?u)\\\\b\\\\w\\\\w+\\\\b', tokenizer=None, use_idf=True,\n",
300 | " vocabulary=None)"
301 | ]
302 | },
303 | "execution_count": 49,
304 | "metadata": {},
305 | "output_type": "execute_result"
306 | }
307 | ],
308 | "source": [
309 | "#使用TF-IDF进行文本转向量处理\n",
310 | "from sklearn.feature_extraction.text import TfidfVectorizer\n",
311 | "tv = TfidfVectorizer(stop_words=stopwords, max_features=3000, ngram_range=(1,2))\n",
312 | "tv.fit(x_train)"
313 | ]
314 | },
315 | {
316 | "cell_type": "markdown",
317 | "metadata": {},
318 | "source": [
319 | "### 机器学习建模\n",
320 | "\n",
321 | "特征和标签已经准备好了,接下来就是建模了。这里我们使用文本分类的经典算法朴素贝叶斯算法,而且朴素贝叶斯算法的计算量较少。特征值是评论文本经过TF-IDF处理的向量,标签值评论的分类共两类,好评是1,差评是0。情感评分为分类器预测分类1的概率值。"
322 | ]
323 | },
324 | {
325 | "cell_type": "code",
326 | "execution_count": 50,
327 | "metadata": {},
328 | "outputs": [
329 | {
330 | "data": {
331 | "text/plain": [
332 | "0.9275308869629356"
333 | ]
334 | },
335 | "execution_count": 50,
336 | "metadata": {},
337 | "output_type": "execute_result"
338 | }
339 | ],
340 | "source": [
341 | "#计算分类效果的准确率\n",
342 | "from sklearn.naive_bayes import MultinomialNB\n",
343 | "from sklearn.metrics import roc_auc_score, f1_score\n",
344 | "classifier = MultinomialNB()\n",
345 | "classifier.fit(tv.transform(x_train), y_train)\n",
346 | "classifier.score(tv.transform(x_test), y_test)"
347 | ]
348 | },
349 | {
350 | "cell_type": "code",
351 | "execution_count": 51,
352 | "metadata": {
353 | "scrolled": false
354 | },
355 | "outputs": [
356 | {
357 | "data": {
358 | "text/plain": [
359 | "0.8971584233148908"
360 | ]
361 | },
362 | "execution_count": 51,
363 | "metadata": {},
364 | "output_type": "execute_result"
365 | }
366 | ],
367 | "source": [
368 | "#计算分类器的AUC值\n",
369 | "y_pred = classifier.predict_proba(tv.transform(x_test))[:,1]\n",
370 | "roc_auc_score(y_test,y_pred)"
371 | ]
372 | },
373 | {
374 | "cell_type": "code",
375 | "execution_count": 52,
376 | "metadata": {},
377 | "outputs": [],
378 | "source": [
379 | "#计算一条评论文本的情感评分\n",
380 | "def ceshi(model,strings):\n",
381 | " strings_fenci = fenci(pd.Series([strings]))\n",
382 | " return float(model.predict_proba(tv.transform(strings_fenci))[:,1])"
383 | ]
384 | },
385 | {
386 | "cell_type": "code",
387 | "execution_count": 53,
388 | "metadata": {},
389 | "outputs": [
390 | {
391 | "name": "stdout",
392 | "output_type": "stream",
393 | "text": [
394 | "好评实例的模型预测情感得分为0.8638082706675478\n",
395 | "差评实例的模型预测情感得分为0.7856544482460911\n"
396 | ]
397 | }
398 | ],
399 | "source": [
400 | "#从大众点评网找两条评论来测试一下\n",
401 | "test1 = '很好吃,环境好,所有员工的态度都很好,上菜快,服务也很好,味道好吃,都是用蒸馏水煮的,推荐,超好吃' #5星好评\n",
402 | "test2 = '糯米外皮不绵滑,豆沙馅粗躁,没有香甜味。12元一碗不值。' #1星差评\n",
403 | "print('好评实例的模型预测情感得分为{}\\n差评实例的模型预测情感得分为{}'.format(ceshi(classifier,test1),ceshi(classifier,test2)))"
404 | ]
405 | },
406 | {
407 | "cell_type": "markdown",
408 | "metadata": {},
409 | "source": [
410 | "可以看出,准确率和AUC值都非常不错的样子,但点评网上的实际测试中,5星好评模型预测出来了,1星差评缺预测错误。为什么呢?我们查看一下**混淆矩阵**"
411 | ]
412 | },
413 | {
414 | "cell_type": "code",
415 | "execution_count": 54,
416 | "metadata": {
417 | "scrolled": true
418 | },
419 | "outputs": [
420 | {
421 | "data": {
422 | "text/plain": [
423 | "array([[ 46, 385],\n",
424 | " [ 8, 4984]], dtype=int64)"
425 | ]
426 | },
427 | "execution_count": 54,
428 | "metadata": {},
429 | "output_type": "execute_result"
430 | }
431 | ],
432 | "source": [
433 | "from sklearn.metrics import confusion_matrix\n",
434 | "y_predict = classifier.predict(tv.transform(x_test))\n",
435 | "cm = confusion_matrix(y_test, y_predict)\n",
436 | "cm"
437 | ]
438 | },
439 | {
440 | "cell_type": "markdown",
441 | "metadata": {},
442 | "source": [
443 | "可以看出,**负类的预测非常不准**,433单准确预测为负类的只有15.7%,应该是由于**数据不平衡**导致的,模型的默认阈值为输出值的中位数。比如逻辑回归的输出范围为[0,1],当某个样本的输出大于0.5就会被划分为正例,反之为反例。在数据的类别不平衡时,采用默认的分类阈值可能会导致输出全部为正例,产生虚假的高准确度,导致分类失败。\n",
444 | "\n",
445 | "处理样本不均衡问题的方法,首先可以选择调整阈值,使得模型对于较少的类别更为敏感,或者选择合适的评估标准,比如ROC或者F1,而不是准确度(accuracy)。另外一种方法就是通过采样(sampling)来调整数据的不平衡。其中欠采样抛弃了大部分正例数据,从而弱化了其影响,可能会造成偏差很大的模型,同时,数据总是宝贵的,抛弃数据是很奢侈的。另外一种是过采样,下面我们就使用过采样方法来调整。\n",
446 | "\n",
447 | "### 过采样(单纯复制)\n",
448 | "\n",
449 | "单纯的重复了反例,因此会过分强调已有的反例。如果其中部分点标记错误或者是噪音,那么错误也容易被成倍的放大。因此最大的风险就是对反例过拟合。"
450 | ]
451 | },
452 | {
453 | "cell_type": "code",
454 | "execution_count": 55,
455 | "metadata": {
456 | "scrolled": true
457 | },
458 | "outputs": [
459 | {
460 | "data": {
461 | "text/plain": [
462 | "1.0 19916\n",
463 | "0.0 1779\n",
464 | "Name: target, dtype: int64"
465 | ]
466 | },
467 | "execution_count": 55,
468 | "metadata": {},
469 | "output_type": "execute_result"
470 | }
471 | ],
472 | "source": [
473 | "data['target'].value_counts()"
474 | ]
475 | },
476 | {
477 | "cell_type": "code",
478 | "execution_count": 56,
479 | "metadata": {},
480 | "outputs": [],
481 | "source": [
482 | "#把0类样本复制10次,构造训练集\n",
483 | "index_tmp = y_train==0\n",
484 | "y_tmp = y_train[index_tmp]\n",
485 | "x_tmp = x_train[index_tmp]\n",
486 | "x_train2 = pd.concat([x_train,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp,x_tmp])\n",
487 | "y_train2 = pd.concat([y_train,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp,y_tmp])"
488 | ]
489 | },
490 | {
491 | "cell_type": "code",
492 | "execution_count": 57,
493 | "metadata": {},
494 | "outputs": [
495 | {
496 | "data": {
497 | "text/plain": [
498 | "0.9049699937533463"
499 | ]
500 | },
501 | "execution_count": 57,
502 | "metadata": {},
503 | "output_type": "execute_result"
504 | }
505 | ],
506 | "source": [
507 | "#使用过采样样本(简单复制)进行模型训练,并查看准确率\n",
508 | "clf2 = MultinomialNB()\n",
509 | "clf2.fit(tv.transform(x_train2), y_train2)\n",
510 | "y_pred2 = clf2.predict_proba(tv.transform(x_test))[:,1]\n",
511 | "roc_auc_score(y_test,y_pred2)"
512 | ]
513 | },
514 | {
515 | "cell_type": "code",
516 | "execution_count": 58,
517 | "metadata": {
518 | "scrolled": true
519 | },
520 | "outputs": [
521 | {
522 | "data": {
523 | "text/plain": [
524 | "array([[ 331, 100],\n",
525 | " [ 637, 4355]], dtype=int64)"
526 | ]
527 | },
528 | "execution_count": 58,
529 | "metadata": {},
530 | "output_type": "execute_result"
531 | }
532 | ],
533 | "source": [
534 | "#查看此时的混淆矩阵\n",
535 | "y_predict2 = clf2.predict(tv.transform(x_test))\n",
536 | "cm = confusion_matrix(y_test, y_predict2)\n",
537 | "cm"
538 | ]
539 | },
540 | {
541 | "cell_type": "markdown",
542 | "metadata": {},
543 | "source": [
544 | "可以看出,即使是简单粗暴的复制样本来处理样本不平衡问题,负样本的识别率大幅上升了,变为77%,满满的幸福感呀~我们自己写两句评语来看看"
545 | ]
546 | },
547 | {
548 | "cell_type": "code",
549 | "execution_count": 59,
550 | "metadata": {
551 | "scrolled": false
552 | },
553 | "outputs": [
554 | {
555 | "data": {
556 | "text/plain": [
557 | "0.3520907656917545"
558 | ]
559 | },
560 | "execution_count": 59,
561 | "metadata": {},
562 | "output_type": "execute_result"
563 | }
564 | ],
565 | "source": [
566 | "ceshi(clf2,'排队人太多,环境不好,口味一般')"
567 | ]
568 | },
569 | {
570 | "cell_type": "markdown",
571 | "metadata": {},
572 | "source": [
573 | "可以看出把0类别的识别出来了,太棒了~"
574 | ]
575 | },
576 | {
577 | "cell_type": "markdown",
578 | "metadata": {},
579 | "source": [
580 | "### 过采样(SMOTE算法)\n",
581 | "\n",
582 | "SMOTE(Synthetic minoritye over-sampling technique,SMOTE),是在局部区域通过K-近邻生成了新的反例。相较于简单的过采样,SMOTE降低了过拟合风险,但同时运算开销加大\n",
583 | "\n",
584 | "对SMOTE感兴趣的同学可以看下这篇文章https://www.jianshu.com/p/ecbc924860af"
585 | ]
586 | },
587 | {
588 | "cell_type": "code",
589 | "execution_count": 60,
590 | "metadata": {},
591 | "outputs": [],
592 | "source": [
593 | "#使用SMOTE进行样本过采样处理\n",
594 | "from imblearn.over_sampling import SMOTE\n",
595 | "oversampler=SMOTE(random_state=0)\n",
596 | "x_train_vec = tv.transform(x_train)\n",
597 | "x_resampled, y_resampled = oversampler.fit_sample(x_train_vec, y_train)"
598 | ]
599 | },
600 | {
601 | "cell_type": "code",
602 | "execution_count": 61,
603 | "metadata": {},
604 | "outputs": [
605 | {
606 | "data": {
607 | "text/plain": [
608 | "1.0 14920\n",
609 | "0.0 1348\n",
610 | "Name: target, dtype: int64"
611 | ]
612 | },
613 | "execution_count": 61,
614 | "metadata": {},
615 | "output_type": "execute_result"
616 | }
617 | ],
618 | "source": [
619 | "#原始的样本分布\n",
620 | "y_train.value_counts()"
621 | ]
622 | },
623 | {
624 | "cell_type": "code",
625 | "execution_count": 62,
626 | "metadata": {
627 | "scrolled": true
628 | },
629 | "outputs": [
630 | {
631 | "data": {
632 | "text/plain": [
633 | "1.0 14920\n",
634 | "0.0 14920\n",
635 | "dtype: int64"
636 | ]
637 | },
638 | "execution_count": 62,
639 | "metadata": {},
640 | "output_type": "execute_result"
641 | }
642 | ],
643 | "source": [
644 | "#经过SMOTE算法过采样后的样本分布情况\n",
645 | "pd.Series(y_resampled).value_counts()"
646 | ]
647 | },
648 | {
649 | "cell_type": "markdown",
650 | "metadata": {},
651 | "source": [
652 | "我们经过插值,把0类数据也丰富为14923个数据了,这时候正负样本的比例为1:1,接下来我们用平衡后的数据进行训练,效果如何呢,好期待啊~"
653 | ]
654 | },
655 | {
656 | "cell_type": "code",
657 | "execution_count": 63,
658 | "metadata": {
659 | "scrolled": true
660 | },
661 | "outputs": [
662 | {
663 | "data": {
664 | "text/plain": [
665 | "0.9072990102028675"
666 | ]
667 | },
668 | "execution_count": 63,
669 | "metadata": {},
670 | "output_type": "execute_result"
671 | }
672 | ],
673 | "source": [
674 | "#使用过采样样本(SMOTE)进行模型训练,并查看准确率\n",
675 | "clf3 = MultinomialNB()\n",
676 | "clf3.fit(x_resampled, y_resampled)\n",
677 | "y_pred3 = clf3.predict_proba(tv.transform(x_test))[:,1]\n",
678 | "roc_auc_score(y_test,y_pred3)"
679 | ]
680 | },
681 | {
682 | "cell_type": "code",
683 | "execution_count": 64,
684 | "metadata": {
685 | "scrolled": false
686 | },
687 | "outputs": [
688 | {
689 | "data": {
690 | "text/plain": [
691 | "array([[ 330, 101],\n",
692 | " [ 601, 4391]], dtype=int64)"
693 | ]
694 | },
695 | "execution_count": 64,
696 | "metadata": {},
697 | "output_type": "execute_result"
698 | }
699 | ],
700 | "source": [
701 | "#查看此时的准确率\n",
702 | "y_predict3 = clf3.predict(tv.transform(x_test))\n",
703 | "cm = confusion_matrix(y_test, y_predict3)\n",
704 | "cm"
705 | ]
706 | },
707 | {
708 | "cell_type": "code",
709 | "execution_count": 65,
710 | "metadata": {
711 | "scrolled": true
712 | },
713 | "outputs": [
714 | {
715 | "data": {
716 | "text/plain": [
717 | "0.23491893934922978"
718 | ]
719 | },
720 | "execution_count": 65,
721 | "metadata": {},
722 | "output_type": "execute_result"
723 | }
724 | ],
725 | "source": [
726 | "#到网上找一条差评来测试一下情感评分的预测效果\n",
727 | "test3 = '糯米外皮不绵滑,豆沙馅粗躁,没有香甜味。12元一碗不值。'\n",
728 | "ceshi(clf3,test3)"
729 | ]
730 | },
731 | {
732 | "cell_type": "markdown",
733 | "metadata": {},
734 | "source": [
735 | "可以看出,使用SMOTE插值与简单的数据复制比起来,AUC率略有提高,实际预测效果也挺好\n",
736 | "\n",
737 | "### 模型评估测试\n",
738 | "\n",
739 | "接下来我们把3W条数据都拿来训练,数据量变多了,模型效果应该会更好"
740 | ]
741 | },
742 | {
743 | "cell_type": "code",
744 | "execution_count": 66,
745 | "metadata": {
746 | "scrolled": true
747 | },
748 | "outputs": [],
749 | "source": [
750 | "#词向量训练\n",
751 | "tv2 = TfidfVectorizer(stop_words=stopwords, max_features=3000, ngram_range=(1,2))\n",
752 | "tv2.fit(data_model['cus_comment'])\n",
753 | "\n",
754 | "#SMOTE插值\n",
755 | "X_tmp = tv2.transform(data_model['cus_comment'])\n",
756 | "y_tmp = data_model['target']\n",
757 | "sm = SMOTE(random_state=0)\n",
758 | "X,y = sm.fit_sample(X_tmp, y_tmp)\n",
759 | "\n",
760 | "clf = MultinomialNB()\n",
761 | "clf.fit(X, y)\n",
762 | "\n",
763 | "def fenxi(strings):\n",
764 | " strings_fenci = fenci(pd.Series([strings]))\n",
765 | " return float(clf.predict_proba(tv2.transform(strings_fenci))[:,1])"
766 | ]
767 | },
768 | {
769 | "cell_type": "code",
770 | "execution_count": 67,
771 | "metadata": {},
772 | "outputs": [
773 | {
774 | "data": {
775 | "text/plain": [
776 | "0.28900092243477077"
777 | ]
778 | },
779 | "execution_count": 67,
780 | "metadata": {},
781 | "output_type": "execute_result"
782 | }
783 | ],
784 | "source": [
785 | "#到网上找一条差评来测试一下\n",
786 | "fenxi('糯米外皮不绵滑,豆沙馅粗躁,没有香甜味。12元一碗不值。')"
787 | ]
788 | },
789 | {
790 | "cell_type": "markdown",
791 | "metadata": {},
792 | "source": [
793 | "只用到了简单的机器学习,就做出了不错的情感分析效果,知识的力量真是强大呀,666~\n",
794 | "### 后续优化方向\n",
795 | "\n",
796 | "- 使用更复杂的机器学习模型如神经网络、支持向量机等\n",
797 | "- 模型的调参\n",
798 | "- 行业词库的构建\n",
799 | "- 增加数据量\n",
800 | "- 优化情感分析的算法\n",
801 | "- 增加标签提取等\n",
802 | "- 项目部署到服务器上,更好地分享和测试模型的效果"
803 | ]
804 | }
805 | ],
806 | "metadata": {
807 | "kernelspec": {
808 | "display_name": "Python 3",
809 | "language": "python",
810 | "name": "python3"
811 | },
812 | "language_info": {
813 | "codemirror_mode": {
814 | "name": "ipython",
815 | "version": 3
816 | },
817 | "file_extension": ".py",
818 | "mimetype": "text/x-python",
819 | "name": "python",
820 | "nbconvert_exporter": "python",
821 | "pygments_lexer": "ipython3",
822 | "version": "3.6.5"
823 | }
824 | },
825 | "nbformat": 4,
826 | "nbformat_minor": 2
827 | }
828 |
--------------------------------------------------------------------------------