前言:这是我学数据分析以来,第一次用python进行数据分析实战,一边做,一遍看我平时做的笔记,查看别人的博客,同时也新加了很多我重来没有学过的新功能,幸不辱命,协助完成了一篇上档次的纯python毕业论文,以上所用到的数据均来自我爬取的《太平洋汽车》点评和论坛。学习编程真的是这样,如果自己不进行实战操作,永远不知道自己会遇见什么问题,也无从提升自己的能力,这是一个好的开始,简单的梳理一下自己所做的数据分析模块吧!
操作环境: windows10,jupyter notebook,谷歌浏览器
数据下载: https://www.lanzous.com/i9rq8af
爬取数据博客: 学习python爬虫看一篇就足够了之爬取《太平洋汽车》论坛及点评实战爬虫大全
分析要求:
这个是我自己列出的分析要求,自己对数据分析也不是很了解,就是在获取数据的时候觉得哪些数据可以用来做哪些统计或分析,所以就把要求之外的数据也获取下来备用,想不到后来对我的学习还真的排上了用场。而且对于做毕业论文,选择这个网页的数据是非常明智的,因为它有丰富的信息供自己研究使用,如用户,时间,地点,评分,评价等,它们直接就是分好类的,所以对于研究数据分析,简直就是太方便了。
我一共爬取了三种车的数据作为研究对象,这里只以排在第一的 大众朗逸轿车 做为研究对象进行分析
(1)导入python相关库
import numpy as np
import pandas as pd
from pandas import Series, DataFrame
import matplotlib.pyplot as plt
%matplotlib inline
如果自己的电脑上面没有安装这几个库,可以直接使用 pip install numpy
进行安装。
(2)导入“太平洋汽车_朗逸轿车.xlsx”
data = pd.read_excel("./太平洋汽车_朗逸轿车.xlsx") #读入数据
data.head() #显示前五行
车主 | 发表时间 | 购买车型 | 购买时间 | 地点 | 价格 | 价格单位 | 平均油耗 | 油耗单位 | 行驶里程(公里) | ... | 优点 | 缺点 | 外观 | 内饰 | 空间 | 配置 | 动力 | 操控 | 油耗 | 舒适 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 137926969XX | 2020-01-31 | 朗逸2019款朗逸启航1.5L 自动风尚版国VI | 2020-01-01 | 北京市北京 | 11.99 | 万元 | 8.0 | L/100km | 560 | ... | 我喜欢这种风格,如果你也喜欢,那我们可能是一路人,科幻时尚年轻的感觉啦,开着很棒 | 油耗有点高,可能是我自己还没开习惯这车 | 外观就是好看,线条很好,肌肉大气感是特别的存在 | 内饰设计师绝对的不错,科技感,豪华感满满,档把超酷 | 空间一流,还可以的吧,坐姿挺高的 | 配置很不错,该有的配置都有了,功能挺多的,我很满意。 | 起步要给点油,动力都很棒,速能力有目共睹,起步稍弱,但个人觉得加好点的油可以弥补这个缺点,大... | 方向盘控制的是很好的,很轻,用着真舒服,别的轿车方向盘也没有这个用着舒服。 | 跟官方称出入不大,现在还是新车状态吧,还的看看接下来的表现,满意是在预期状态吧 | 车子坐起来舒不舒服特别重要,这款车子就挺好,座椅够软,够质感。 |
1 | 开心就好笑笑笑 | 2020-01-30 | 朗逸2019款1.5L自动视野版国VI | 2020-01-01 | 云南昆明 | 13.69 | 万元 | 7.5 | L/100km | 340 | ... | 外观帅气时尚,更多还是在这么多品牌里面觉得他不错,价位里面也没什么其他选择了,适合年轻人,运... | 最不满意的就是避震太不好了,是偏运动 | 相当满意,就是看中的外观,精巧时尚的风格 | 时尚新颖,一看就是很符合年轻人的口味,尤其是多功能的大屏看起来就很有科技感。 | 空间上就我来说够用了,前排空间比较大一些,对驾驶员的来说更舒适一些开着也很舒适。 | 动力好标配配置:显示屏,倒影,雷达标配。 | 中规中矩,舍得给油也可以开得很轻快,安静速度提的也不错。 | 操控很准,指哪打哪,转向准,路感舒适,但还是可以听到不小的胎噪声音。 | 最近跑了一趟长途,高速全空调加上部分接近百公里的城镇道路,7L左右,靠谱了 | 舒适性性还可以吧,偏运动也能很强,其实说也很合格吧,空间的话坐的人不多的时候问题不大。 |
2 | hongfeng0417 | 2020-01-30 | 朗逸2019款朗逸启航1.5L手动风尚版国VI | 2020-01-01 | 黑龙江牡丹江 | 9.99 | 万元 | 9.0 | L/100km | 420 | ... | 用车一小段时间了,说不上什么特别满意的,整体来说比较均衡,没有什么特别突出,自己喜欢就是了 | 空间确实是一般吧 | 外观上猛然看上去很年轻时尚吧,但是时间长细看总有种不协调的感觉,相对来说大一款更合适 | 不错,做工再好一点就更好了,用料也符合这个,没什么太大的毛病。 | 家用,够了,前后排的空间给我的感受很好,车的后备厢大小也不在话下。 | 配置情况还可以,我觉得好用的话也得配上 | 油门多踩一点就很冲,上坡时,的确有点肉,高速上跑起来没有问题,感觉很好。 | 操控性只能说一般偏上的水平吧。刹车和油门还不错,都挺轻的。 | 这个跟官方的数据也差不多。我走的大多是城市公路路,偶尔跑跑高速。 | 车子整体的舒适度还是可以的,不过就是坐垫的质量一般,路不好时也会出现一些颠簸感。 |
3 | jdikio | 2020-01-30 | 朗逸2019款朗逸启航1.5L手动舒适版国VI | 2020-01-01 | 北京市北京 | 11.09 | 万元 | 9.8 | L/100km | 460 | ... | 外形犀利感强了,这车开起来吧,高大稳重,很有安全感,舒适性程度很高,座椅的舒服柔软,车内的隔... | 油耗有点高,动力一般般。 | 外观高大,硬朗,空间也很好,前脸的大气特别好,开出去也觉得很有面子。 | 内饰布局方便,按键位置合理,坐在车里面的豪华感氛围很不错。 | 空间肯定没什么问题,和几个同事外出很方便,作为工作车。 | 配置很好,没什么可挑出来的毛病,一般的方便配置都有。 | 动力中中等等,人坐多变肉了,油耗也高挺多的。 | 开起来还是挺不错的,挺稳,好开,驾乘都好。 | 稍微觉得油耗高一些,排量不大,我觉得可以降低一点。 | 舒适性好,车的隔音效果不错,噪音小,车内聊天很安静,驾驶座宽敞,视野好 |
4 | sailor_1205 | 2020-01-27 | 朗逸2019款朗逸启航1.5L自动舒适版国VI | 2020-01-01 | 广东深圳 | 11.29 | 万元 | 7.4 | L/100km | 500 | ... | 大致上我都是较为满意的,除了内饰之外,要不然也不会选择这款车了。我觉得动力吧,动力是最满意的地方 | 内饰自我感觉塑料感有点点不满意吧。 | 我爸说这整车时尚运动的造型,屁股也非常耐看,尾灯很有标志性。 | 内饰可以说比较一般嘛,质感,不是很精美,不是很吸引人吧。 | 空间足够大,一家人出游感觉绰绰有余了。 | ABS防抱死,刹车辅助,牵引力控制等等,用料不错不错。 | 因为我开车温柔不爱乱超车。。开着很不错。。也没他们说的动力肉的感觉啊。。过红灯的时候也没让人... | 方向指向准确,A柱宽大有点遮挡视线,急踩油门延迟1秒后推背,刹车及悬挂调教合适舒服 | 目前油耗差不多是7.4,有时走走停停就高点8.2那样。 | 座椅包裹感填充一般,软硬度适中 |
(3)查看数据形状
data.shape
(4682, 28)
结果分析: 表示该表格的数据一共有4682条(行),每天数据有28列
1、整行去重。
DataFrame.drop_duplicates()
2、按照其中某一列或多列去重
DataFrame.drop_duplicates(subset=[‘列名1’,‘列名2’])
data.drop_duplicates(subset=None, keep='first', inplace=True)#去除行相同的数据
data.shape # 查看去重后的结果
(4516, 28)
结果分析: 这个方法去掉的是行数据,原数据有 4682 行,去重后有 4516行。
# 车主去重
data['车主'].unique()
array(['137926969XX', '开心就好笑笑笑', 'hongfeng0417', ..., '春暖花开的节操',
'婴宁是不会输的', '名字太长了'], dtype=object)
#去重后的数量
data['车主'].unique().shape
(4459,)
#这里以重复评论的人当作忠实粉丝
fans = data.shape[0] - data['车主'].unique().shape[0]
print ("该型号车的粉丝数为:", fans)
该型号车的粉丝数为: 57
结果分析: 如果我们以假设的条件且假设成立,重复评论的人当作忠实粉丝,那么在该数据中一个有57个忠实粉丝。
data[data.duplicated(['车主'])]
结果分析: 我们以车主中重复数据为条件,提取出57行 * 28列
数据,包含了该车主的评论数据,也验证了上面方法的正确性。
data['购买车型'].unique().shape
(87,)
结果分析: 这里一共拥有87种车型
value_counts()
函数进行频率统计,它的结果自动按降序排列,截取出前十个就是 1~10 名。sort_7 = data['购买车型'].value_counts()[:10]
sort_7
朗逸2013款经典款1.6L自动舒适版 460
朗逸2013款改款1.4TSIDSG舒适版 445
朗逸2015款1.6L手动舒适版 432
朗逸2013款经典款1.6L手动舒适版 368
朗逸2013款经典款1.6L手动风尚版 318
朗逸2015款1.6L自动舒适版 306
朗逸2013款改款1.4TSI手动舒适版 233
朗逸2015款1.6L手动风尚版 149
朗逸2015款1.6L自动风尚版 146
朗逸2013款1.4TSIDSG舒适版 123
Name: 购买车型, dtype: int64
# 绘制前10名的饼状图
plt.figure(figsize=(8, 8))#设置图片比例
sort_7.plot(kind='pie', autopct='%1.2f%%',) #绘制饼图,保留两位百分数
plt.title("大众_朗逸前10销量占比图")
plt.savefig("./images/大众_朗逸前10销量占比图.png")
plt.show()
data['购买时间'] = pd.to_datetime(data['购买时间']) #数据类型转换
data['购买时间'] = data['购买时间'].map(lambda x: x.strftime('%Y/%m')) #转为年/月
data['购买时间']
0 2020/01
1 2020/01
2 2020/01
3 2020/01
4 2020/01
...
4677 2012/09
4678 2012/09
4679 2013/01
4680 2013/01
4681 2012/08
Name: 购买时间, Length: 4516, dtype: object
x_buy_time = data['购买时间'].value_counts()#统计相同时间出现的次数
x_buy_time = x_buy_time.sort_index(axis=0)#按索引排序
plt.figure(figsize=(8, 4))#设置图片比例
x_buy_time.plot(kind='line') #x_buy_count[::-1]转置数据
plt.title("大众轿车_朗逸购买日期详情评论趋势图")
plt.xlabel("年/月")
plt.ylabel("数量(辆)")
plt.savefig("./images/大众轿车_朗逸购买日期详情评论趋势图.png")#保存图片
plt.show()
x_buy_time_y = pd.to_datetime(data['购买时间']).map(lambda x: x.strftime('%Y')).value_counts()
x_buy_time_y = x_buy_time_y.sort_index(axis=0)
x_buy_time_y.plot(kind='line')
plt.title("大众轿车_朗逸购买年评论趋势图")
plt.xlabel("年份")
plt.ylabel("数量(辆)")
plt.savefig("./images/大众轿车_朗逸购买日期评论趋势图.png")#保存图片
plt.show()
x_share_times = pd.to_datetime(data['发表时间']).map(lambda x: x.strftime('%Y')).value_counts(ascending=False)
x_share_time = x_share_times.sort_index(axis=0)
x_share_time.plot(kind='line')
plt.title("大众轿车_朗逸评论时间趋势图")
plt.xlabel("年")
plt.ylabel("数量(辆)")
plt.savefig("./images/大众轿车_朗逸评论时间趋势图.png")#保存图片
plt.show()
结果分析: 从上面的购车时间和评论时间可以看出,2013年的购车量是最大的,2017年发表的评论是最多的;从网页上朗逸的排名了看,它的趋势不应该会呈下降趋势呀,这里有很多可能因素造成了这样的结果
接下了查看 发表时间 和 购买时间 有什么关系
# 计算时间差并排序
data['时间差'] = pd.to_datetime(data['发表时间']) - pd.to_datetime(data['购买时间'])
data['时间差'].sort_values()
4368 -43 days
4434 -43 days
4469 -43 days
4476 -43 days
4483 -43 days
...
86 3351 days
159 3357 days
99 3377 days
81 3567 days
708 5798 days
Name: 时间差, Length: 4516, dtype: timedelta64[ns]
结果分析: 从上面的结果看出,用发布时间减去购车时间,有很多值居然为负数,就相当于还没有买车就评论,很明显这个数据为异常值,我们在研究时间关系时,必须先把它去掉才不会影响到正常值。同时也可以反映,这个点评的网页页面功能有所缺陷,不应该让发布时间比购车时间大,这也有可能是影响上面结果的原因之一。
结果分析: 一共有76条数据存在异常情况,去掉异常数据后还有4430条数据正常,可以供我们研究使用。
buy_share_time = pd.to_datetime(normal_time['发表时间']) - pd.to_datetime(normal_time['购买时间']) #时间差
buy_share_time.describe() #描述统计信息
count 4430 #总数
mean 1330 days 12:23:04.740406 #平均值
std 807 days 21:59:19.897105 #方差
min 0 days 00:00:00 #最小值
25% 658 days 00:00:00 #四分位值
50% 1492 days 00:00:00 #中值
75% 1857 days 00:00:00 #四分位值
max 5798 days 00:00:00 #最大值
dtype: object
结果分析: 从上面的结果可以看出,大多数用户都是在买车后近4年才开始评论,重商业上了说,这个值至关重要,最好至少要在4年左右的时间保证车辆的质量和服务,可以提高用户的满意值。
plt.plot(normal_time['时间差'].dt.days,'.',c='r')
plt.title("大众轿车_朗逸评论与购买时间差分布图")
plt.savefig("./images/大众轿车_朗逸评论与购买时间差分布图.png")#保存图片
plt.show()
结果分析: 从图中可以看出,用户评论的时间集中在3000天以下,在1000~2000这个范围是最集中的,其中还发现一共异常值,5000以上,其他的数据都没有超过4000,估计会对时间数据分析有略微的影响。
#查看表头
data.columns
Index(['车主', '发表时间', '购买车型', '购买时间', '地点', '价格', '价格单位', '平均油耗', '油耗单位',
'行驶里程(公里)', '外观评分', '内饰评分', '空间评分', '配置评分', '动力评分', '操控评分', '油耗评分',
'舒适评分', '优点', '缺点', '外观', '内饰', '空间', '配置', '动力', '操控', '油耗', '舒适',
'时间差'],
dtype='object')
为什么要选择2013年的数据进行研究呢?主要考虑到一下原因:
import datetime
s_date = datetime.datetime.strptime('20130101', '%Y%m%d').date() #开始时间
e_date = datetime.datetime.strptime('20131231', '%Y%m%d').date() #结束时间
df = data[(pd.to_datetime(data['购买时间']) >= s_date) & (pd.to_datetime(data['购买时间']) <= e_date)] #选择条件
df.shape #(1190, 28)
df.head()
表格中的数据运算在DataFrame下可以直接进行运算,如果把它转换为字符型后,加法运算为拼接功能。
df['综合评分'] = (df['外观评分'] + df['内饰评分'] + df['空间评分'] + df['配置评分'] + df['动力评分'] + df['操控评分'] + df['油耗评分'] +df['舒适评分']) / 8
df.head()
df[['综合评分', '价格']].corr()
综合评分 | 价格 | |
---|---|---|
综合评分 | 1.000000 | 0.048849 |
价格 | 0.048849 | 1.000000 |
结果分析: 从上面的结果可以看出,综合评分和价格几乎没有任何关系,它的值很接近0,表示相关性很低。
sim_dis = pd.DataFrame([],
index=['综合评分', '购买车型', '价格'],
columns=['综合评分', '购买车型', '价格'])
for i in ['综合评分', '购买车型', '价格']:
for j in ['综合评分', '购买车型', '价格']:
sim_dis.loc[i,j] = df[i].equals(df[j])
sim_dis
综合评分 | 购买车型 | 价格 | |
---|---|---|---|
综合评分 | True | False | False |
购买车型 | False | True | False |
价格 | False | False | True |
结果分析: 如果相关系数大于0.5则为True,否则为False,说明它们之间都没有明显的关系。
df[['平均油耗', '行驶里程(公里)']].corr()
平均油耗 | 行驶里程(公里) | |
---|---|---|
平均油耗 | 1.000000 | -0.018131 |
行驶里程(公里) | -0.018131 | 1.000000 |
结果分析: 上面的结果返回的数据为负值,说明它们的影响关系为负相关,行驶公里长往往更能节约油耗,但是由于相关系数接近于0,所以效果并不是很明显。
现在要做的是一个汽车销量的全国分布图,把出现省份的次数多少转换为颜色深浅填充进中国地图之中,所以要先统计出每个省出现的次数,为了数据的直观性,我直接把它们转化为字典型数据。
(1)查看地点中所有的城市
data['地点'].unique() #地点去重后的结果
array(['北京市北京', '云南昆明', '黑龙江牡丹江', '广东深圳', '广东中山', '浙江杭州', '四川广安', '江苏南京',
'天津市天津', '河北邢台', '湖南长沙', '江西萍乡', '山东临沂', '广东佛山', '安徽合肥', '江苏盐城',
'湖北荆门', '四川巴中', '山东潍坊', '四川成都', '江苏泰州', '福建福州', '湖北潜江', '河南郑州',
'广东广州', '陕西西安', '贵州遵义', '山东青岛', '新疆乌鲁木齐', '山东滨州', '青海西宁', '上海市上海',
'河北保定', '广东汕尾', '吉林长春', '广东东莞', '内蒙古包头', '江西上饶', '河南洛阳', '山东济南',
'陕西宝鸡', '江苏常州', '河北石家庄', '江苏苏州', '河北承德', '河南焦作', '山西太原', '安徽六安',
'陕西咸阳', '河南南阳', '河南商丘', '贵州贵阳', '山东泰安', '河北廊坊', '江苏连云港', '福建龙岩',
'河南新乡', '辽宁鞍山', '山西运城', '新疆克拉玛依', '湖南邵阳', '河北邯郸', '新疆阿克苏', '山东济宁',
'福建厦门', '陕西榆林', '江苏淮安', '甘肃兰州', '浙江台州', '广西北海', '山东枣庄', '山东东营',
'重庆市重庆', '浙江丽水', '安徽淮北', '浙江舟山', '河南安阳', '内蒙古呼和浩特', '山东日照', '辽宁沈阳',
'广西南宁', '山西晋中', '浙江宁波', '广东肇庆', '内蒙古鄂尔多斯', '安徽马鞍山', '山西晋城', '山东淄博',
'辽宁锦州', '湖北襄阳', '四川德阳', '黑龙江大庆', '浙江温州', '江苏无锡', '河南平顶山', '山东聊城',
'广东江门', '山东烟台', '四川乐山', '江西南昌', '湖北黄石', '山东菏泽', '安徽宿州', '江苏南通',
'浙江绍兴', '安徽芜湖', '安徽阜阳', '河南许昌', '湖北荆州', '黑龙江哈尔滨', '江西赣州', '辽宁大连',
'内蒙古呼伦贝尔', '河北唐山', '广西玉林', '河南三门峡', '湖北武汉', '辽宁营口', '湖南湘西', '山西大同',
'江西新余', '福建泉州', '广东茂名', '宁夏银川', '广西柳州', '湖南娄底', '河南濮阳', '江西景德镇',
'河南信阳', '青海海西', '安徽滁州', '贵州铜仁', '山西临汾', '内蒙古赤峰', '湖南湘潭', '山东威海',
'四川雅安', '湖南郴州', '安徽安庆', '河南周口', '四川宜宾', '甘肃酒泉', '辽宁葫芦岛', '河南开封',
'广西桂林', '广东珠海', '江西宜春', '广西百色', '安徽蚌埠', '云南保山', '四川凉山', '江苏宿迁',
'湖南益阳', '云南曲靖', '湖南怀化', '江苏徐州', '海南海口', '广东梅州', '浙江湖州', '河北衡水',
'江苏扬州', '湖北孝感', '陕西渭南', '浙江嘉兴', '江西九江', '浙江金华', '湖南永州', '河北张家口',
'四川攀枝花', '四川资阳', '海南琼海', '甘肃天水', '内蒙古通辽', '四川自贡', '甘肃嘉峪关', '湖北恩施',
'广东汕头', '四川遂宁', '河北沧州', '安徽淮南', '内蒙古乌海', '江苏镇江', '四川广元', '福建漳州',
'安徽亳州', '山西长治', '内蒙古巴彦淖尔', '云南临沧', '湖南株洲', '广东河源', '贵州黔西南', '山西忻州',
'河北秦皇岛', '吉林吉林', '甘肃定西', '云南昭通', '山东德州', '辽宁丹东', '江西吉安', '河南驻马店',
'湖南岳阳', '山西阳泉', '广西河池', '广东惠州', '江西鹰潭', '辽宁本溪', '安徽宣城', '四川南充',
'广东湛江', '辽宁盘锦', '湖南衡阳', '湖北咸宁', '四川内江', '湖北十堰', '福建南平', '广东韶关',
'浙江衢州', '湖北鄂州', '辽宁抚顺', '四川泸州', '安徽黄山', '陕西延安', '河南鹤壁', '海南三亚',
'甘肃张掖', '湖北黄冈', '山西吕梁', '山西朔州', '广西贵港', '黑龙江双鸭山', '湖南常德', '福建宁德',
'四川绵阳', '新疆塔城', '吉林延边', '贵州六盘水', '湖北随州', '吉林通化', '广东清远', '黑龙江齐齐哈尔',
'云南', '吉林四平', '福建三明', nan, '海南五指山', '贵州黔东南', '贵州黔南', '贵州毕节',
'云南香格里拉', '安徽铜陵', '广东潮州', '云南红河', '西藏山南地区', '江西抚州', '辽宁朝阳', '新疆伊犁',
'宁夏吴忠', '云南楚雄', '湖北仙桃', '辽宁阜新', '广西梧州', '四川眉山', '湖北宜昌', '福建莆田',
'山东莱芜', '辽宁铁岭', '甘肃平凉', '辽宁辽阳', '黑龙江鸡西', '四川达州', '宁夏石嘴山', '陕西汉中',
'新疆昌吉', '甘肃庆阳', '云南大理', '云南迪庆', '吉林松原', '新疆阿勒泰', '广西钦州', '云南文山',
'西藏日喀则地区', '湖南张家界', '内蒙古乌兰察布', '四川甘孜', '黑龙江黑河', '河南济源', '河南漯河',
'新疆阿拉尔', '青海海北', '吉林辽源', '黑龙江佳木斯', '青海海南', '甘肃金昌', '海南万宁', '青海黄南',
'广东云浮', '江苏', '云南西双版纳', '新疆巴州', '内蒙古兴安盟', '西藏昌都地区', '新疆克孜勒苏',
'新疆铁门关', '吉林白城', '云南丽江', '陕西安康', '内蒙古阿拉善盟', '广东揭阳', '新疆图木舒克',
'内蒙古锡林郭勒盟', '四川阿坝', '甘肃甘南', '湖南吉首', '黑龙江绥化', '广西防城港', '天津市天津滨海',
'湖北天门', '云南普洱', '黑龙江鹤岗', '新疆喀什', '海南东方', '黑龙江七台河', '海南儋州', '云南怒江',
'西藏林芝地区', '陕西商洛', '新疆博尔塔拉', '黑龙江大兴安岭', '内蒙古锡林浩特', '甘肃临夏', '吉林白山',
'云南玉溪', '新疆五家渠', '海南文昌', '湖北林区', '宁夏固原', '陕西铜川', '新疆石河子', '甘肃陇南',
'青海海东', '青海果洛', '西藏拉萨', '广西来宾', '湖北神农架', '新疆吐鲁番', '四川广州', '安徽池州',
'青海玉树', '广西贺州', '黑龙江伊春', '甘肃武威', '西藏那曲地区', '新疆和田'], dtype=object)
以上就是表格中所有的地点了,我们需要统计每一个省份出现的次数,只需要截取出前的两个字符就可以了,其中“黑龙江”和“内蒙古”需要重新进行处理。
(2)截取出省份
# 截取地名前两位,相当于省份
sf = data['地点'].str.slice(0,2)
sf
0 北京
1 云南
2 黑龙
3 北京
4 广东
..
4677 北京
4678 广东
4679 四川
4680 福建
4681 山西
Name: 地点, Length: 4516, dtype: object
province_count = sf.value_counts()#统计省份出项的次数,默认降序
province_count = DataFrame(province_count)#把格式转换为DataFrame
province_count
地点 | |
---|---|
江苏 | 474 |
山东 | 433 |
广东 | 320 |
河南 | 281 |
河北 | 274 |
浙江 | 235 |
上海 | 197 |
四川 | 194 |
安徽 | 193 |
湖北 | 184 |
湖南 | 175 |
山西 | 142 |
北京 | 128 |
辽宁 | 126 |
云南 | 117 |
江西 | 115 |
陕西 | 108 |
福建 | 99 |
广西 | 90 |
内蒙 | 77 |
贵州 | 75 |
黑龙 | 65 |
新疆 | 65 |
重庆 | 59 |
甘肃 | 58 |
吉林 | 53 |
天津 | 48 |
海南 | 43 |
青海 | 31 |
宁夏 | 21 |
西藏 | 17 |
province_count_dict = province_count.to_dict(orient='dict')['地点']
province_count_dict
{
'江苏': 474,
'山东': 433,
'广东': 320,
'河南': 281,
'河北': 274,
'浙江': 235,
'上海': 197,
'四川': 194,
'安徽': 193,
'湖北': 184,
'湖南': 175,
'山西': 142,
'北京': 128,
'辽宁': 126,
'云南': 117,
'江西': 115,
'陕西': 108,
'福建': 99,
'广西': 90,
'内蒙': 77,
'贵州': 75,
'黑龙': 65,
'新疆': 65,
'重庆': 59,
'甘肃': 58,
'吉林': 53,
'天津': 48,
'海南': 43,
'青海': 31,
'宁夏': 21,
'西藏': 17}
从上面的数据我们可以看出,“黑龙江”和“内蒙古”还存在问题,需要把它还原
# 升级字典,把黑龙江和内蒙古还原
province_count_dict['黑龙江'] = province_count_dict.pop('黑龙')
province_count_dict['内蒙古'] = province_count_dict.pop('内蒙')
dir_data = province_count_dict
dir_data
{
'江苏': 474,
'山东': 433,
'广东': 320,
'河南': 281,
'河北': 274,
'浙江': 235,
'上海': 197,
'四川': 194,
'安徽': 193,
'湖北': 184,
'湖南': 175,
'山西': 142,
'北京': 128,
'辽宁': 126,
'云南': 117,
'江西': 115,
'陕西': 108,
'福建': 99,
'广西': 90,
'贵州': 75,
'新疆': 65,
'重庆': 59,
'甘肃': 58,
'吉林': 53,
'天津': 48,
'海南': 43,
'青海': 31,
'宁夏': 21,
'西藏': 17,
'黑龙江': 65,
'内蒙古': 77}
width = 1600
height = 800
rect = [0.1, 0.12, 0.8, 0.8]
lat_min = 0
lat_max = 60
lon_min = 77
lon_max = 140
'''全球等经纬投影模式使用以下设置,否则使用上面的对应设置
width = 3000
height = 1500
rect = [0, 0, 1, 1]
lat_min = -90
lat_max = 90
lon_min = 0
lon_max = 360
'''
#设置字体及大小
font_14 = FontProperties(fname='C:/Windows/Fonts/simhei.ttf', size=14)
font_11 = FontProperties(fname='C:/Windows/Fonts/simhei.ttf', size=11)
#填充颜色
handles = [
matplotlib.patches.Patch(color='#FBEFEF', alpha=1, linewidth=0),#<50
matplotlib.patches.Patch(color='#F6CECE', alpha=1, linewidth=0),# 50-99
matplotlib.patches.Patch(color='#F78181', alpha=1, linewidth=0),#100-149
matplotlib.patches.Patch(color='#FE2E2E', alpha=1, linewidth=0),#150-199
matplotlib.patches.Patch(color='#DF0101', alpha=1, linewidth=0),#200-249
matplotlib.patches.Patch(color='#8A0808', alpha=1, linewidth=0),#250-299
matplotlib.patches.Patch(color='#3B0B0B', alpha=1, linewidth=0),#300-400
matplotlib.patches.Patch(color='#190707', alpha=1, linewidth=0),#400人以上
]
#范围标签
labels = [ '50人一下', '50-99人', '100-149人', '150-199人', '200-249人','250-299人','300-400人','400人以上']
#中国省份的经纬度
provincePos = {
"辽宁省":[121.7,40.9],
"吉林省":[124.5,43.5],
"黑龙江省":[125.6,46.5],
"北京市":[116.0,39.9],
"天津市":[117.0,38.7],
"内蒙古自治区":[110.0,41.5],
"宁夏回族自治区":[105.2,37.0],
"山西省":[111.0,37.0],
"河北省":[114.0,37.8],
"山东省":[116.5,36.0],
"河南省":[111.8,33.5],
"陕西省":[107.5,33.5],
"湖北省":[111.0,30.5],
"江苏省":[119.2,32.5],
"安徽省":[115.5,31.8],
"上海市":[121.0,31.0],
"湖南省":[110.3,27.0],
"江西省":[114.0,27.0],
"浙江省":[118.8,28.5],
"福建省":[116.2,25.5],
"广东省":[113.2,23.1],
"台湾省":[120.5,23.5],
"海南省":[108.0,19.0],
"广西壮族自治区":[107.3,23.0],
"重庆市":[106.5,29.5],
"云南省":[101.0,24.0],
"贵州省":[106.0,26.5],
"四川省":[102.0,30.5],
"甘肃省":[103.0,35.0],
"青海省":[95.0,35.0],
"新疆维吾尔自治区":[85.5,42.5],
"西藏自治区":[85.0,31.5],
"香港特别行政区":[115.1,21.2],
"澳门特别行政区":[112.5,21.2]
}
fig = matplotlib.figure.Figure()
fig.set_size_inches(width/100, height/100) # 设置绘图板尺寸
axes = fig.add_axes(rect)
# 兰博托投影模式,局部
m = Basemap(projection='lcc', llcrnrlon=77, llcrnrlat=14, urcrnrlon=140, urcrnrlat=51, lat_1=33, lat_2=45, lon_0=100, ax=axes)
# 兰博托投影模式,全图
# m = Basemap(projection='lcc', llcrnrlon=80, llcrnrlat=0, urcrnrlon=140, urcrnrlat=51, lat_1=33, lat_2=45, lon_0=100, ax=axes)
# 圆柱投影模式,局部
# m = Basemap(llcrnrlon=lon_min, urcrnrlon=lon_max, llcrnrlat=lat_min, urcrnrlat=lat_max, resolution='l', ax=axes)
# 正射投影模式
# m = Basemap(projection='ortho', lat_0=36, lon_0=102, resolution='l', ax=axes)
# 全球等经纬投影模式,
# m = Basemap(llcrnrlon=lon_min, urcrnrlon=lon_max, llcrnrlat=lat_min, urcrnrlat=lat_max, resolution='l', ax=axes)
#m.etopo()
#加载中国地图形状的包
m.readshapefile('./china-shapefiles-master/china', 'province', drawbounds=True)
m.readshapefile('./china-shapefiles-master/china_nine_dotted_line', 'section', drawbounds=True)
m.drawcoastlines(color='black') # 洲际线
m.drawcountries(color='black') # 国界线
m.drawparallels(np.arange(lat_min,lat_max,10), labels=[1,0,0,0]) #画经度线
m.drawmeridians(np.arange(lon_min,lon_max,10), labels=[0,0,0,1]) #画纬度线
pset = set()
for info, shape in zip(m.province_info, m.province):
pname = info['OWNER'].strip('\x00')
fcname = info['FCNAME'].strip('\x00')
if pname != fcname: # 不绘制海岛
continue
#根据省份字典中值得大小对地图着色
for key in dir_data.keys():
if key in pname:
if dir_data[key] < 50:
color = '#FBEFEF'
elif dir_data[key] < 100:
color = '#F6CECE'
elif dir_data[key] < 150:
color = '#F78181'
elif dir_data[key] < 200:
color = '#FE2E2E'
elif dir_data[key] < 250:
color = '#DF0101'
elif dir_data[key] < 300:
color = '#8A0808'
elif dir_data[key] < 350:
color = '#3B0B0B'
else:
color = '#190707'
break
poly = Polygon(shape, facecolor=color, edgecolor=color)
axes.add_patch(poly)
pos = provincePos[pname]
text = pname.replace("自治区", "").replace("特别行政区", "").replace("壮族", "").replace("维吾尔", "").replace("回族", "").replace("省", "").replace("市", "")
if text not in pset:
x, y = m(pos[0], pos[1])
axes.text(x, y, text, fontproperties=font_11, color='#00FFFF')
pset.add(text)
axes.legend(handles, labels, bbox_to_anchor=(0.5, -0.11), loc='lower center', ncol=4, prop=font_14)
axes.set_title("大众轿车——朗逸全国销售分布图", fontproperties=font_14)
FigureCanvasAgg(fig)
fig.savefig('./images/大众轿车——朗逸.png')
博托投影模式,全图:
圆柱投影模式,局部:
正射投影模式:
全球等经纬投影模式:
cpca
库转化为中国的具体位置(省,市,区,县,镇),经纬度,查询重名的地点等等import cpca #用于划分中国的省份
from cpca import drawer #用于画图
import folium #导入地图
from folium.plugins import HeatMap
loc = cpca.transform(data['地点'], cut=False)#转化地点
drawer.draw_locations(loc, "./images/大众轿车——朗逸用户分布图.html")#画出具体地点
import pandas as pd #导入pandas命名为pd #pip install pandas
from wordcloud import WordCloud #导入词云库 pip install wordcloud
from wordcloud import ImageColorGenerator # 获取图片像素值
from matplotlib.image import imread #读取图片 #pip install matplotlib
import matplotlib.pyplot as plt #显示图片
import jieba.analyse #结巴分析,#pip install jieba
(1)提取范围
#截取出表格中文本列的数据
data.iloc[:, 18:].head()
data.iloc[:, 18:].columns
Index(['优点', '缺点', '外观', '内饰', '空间', '配置', '动力', '操控', '油耗', '舒适'], dtype='object')
(3)把表格中的文本遍历出来
txts = [] #临时存放遍历出来的文本
def get_text(datas):
for txt in datas:
#把文本去掉首位空格,空值nan和换行
txts.append(str(txt).strip().replace("nan", "").replace("\n", ""))
col = data.iloc[:, 18:]#截取出需要提取的数据
for k in range(len(col.columns)):#遍历每一个表头对应的数据
head = col.columns[k]
datas = col[head]
get_text(datas)
#把上面的评论和回复转化成字符串
text = ' '.join(txts) #数组转字符串拼接的方法
# 把数据保存到本地txt文件
with open("./text.txt", 'w', encoding='UTF-8') as f:
f.write(text)
f.close()
# f = open("./text.txt", "r", encoding="utf-8") #打开一个文本
# text = f.read()#读取文本内容
cut_text = jieba.cut(text, cut_all=False) #False,精准;True,全能。# 结果为数组
cut_text = ' '.join(cut_text) #把数组拼接为字符串
word_cloud = WordCloud(font_path="C:/Windows/Fonts/simhei.ttf",
background_color="white",#背景
max_words=800, #画布字体个数
max_font_size=180,#最大字体
min_font_size=40,#最小字体
width=1920,
height=1080).generate(cut_text)#传入分词文本
#定义图片的画布
plt.figure(figsize=(16, 9))#设置画布大小
plt.imshow(word_cloud, interpolation="bilinear")
plt.axis("off")
word_cloud.to_file('./images/词云1.png')#保存图片
plt.show()#展示图片
from snownlp import SnowNLP
text = '我热爱机器学习技术'
s = SnowNLP(text)
#1.分词
s_token = s.words
print(s_token)
['我', '热爱', '机器', '学习', '技术']
s_tags = s.tags
for token_tag in s_tags:
print(token_tag)
('我', 'r')
('热爱', 'v')
('机器', 'n')
('学习', 'v')
('技术', 'n')
#3.情感分析(消极或者积极) positive or negative
s_senti = s.sentiments #(positive的概率)
print(s_senti)
0.9539851857793564
但是,它还有很明显的缺点,如果文本太长,那么它的结果总是为1,所以对于很大的文本,我们必须把它切片后再进行分析。如:
from snownlp import SnowNLP
text = '''我不戴紧箍救不了她,
戴了紧箍爱不了她。一万年太久只争朝夕,
一路走来才发现没有什么是永垂不朽。
我们终于懂得曾经离我们一步之遥的人,一旦错过,
之后哪怕化身绝世英雄,身披金甲战衣,脚踏七彩祥云,一跃八千里,也未必追的回来。
'''
result = SnowNLP(text)
b = result.sentiments #float
print("%.2f" % b)
1.00
print (s.pinyin)
['wo', 're', 'ai', 'ji', 'qi', 'xue', 'xi', 'ji', 'shu']
from snownlp import SnowNLP
text = "貴州財經大學"
print (SnowNLP(text).han)
贵州财经大学
from snownlp import SnowNLP
text = '''我不戴紧箍救不了她,
戴了紧箍爱不了她。一万年太久只争朝夕,
一路走来才发现没有什么是永垂不朽。
我们终于懂得曾经离我们一步之遥的人,一旦错过,
之后哪怕化身绝世英雄,身披金甲战衣,脚踏七彩祥云,一跃八千里,也未必追的回来。
'''
result = SnowNLP(text)
keys = result.keywords(4)
print (keys)
['身', '戴', '紧', '一路']
from snownlp import SnowNLP
sentense = '''我不戴紧箍救不了她,
戴了紧箍爱不了她。一万年太久只争朝夕,
一路走来才发现没有什么是永垂不朽。
我们终于懂得曾经离我们一步之遥的人,一旦错过,
之后哪怕化身绝世英雄,身披金甲战衣,脚踏七彩祥云,一跃八千里,也未必追的回来。
'''
result = SnowNLP(sentense)
summary = result.summary(3)
print (summary)
['我不戴紧箍救不了她', '戴了紧箍爱不了她', '之后哪怕化身绝世英雄']
from snownlp import SnowNLP
text = '''
我不戴紧箍救不了她,
戴了紧箍爱不了她。一万年太久只争朝夕,
一路走来才发现没有什么是永垂不朽。
我们终于懂得曾经离我们一步之遥的人,一旦错过,
之后哪怕化身绝世英雄,身披金甲战衣,脚踏七彩祥云,一跃八千里,也未必追的回来。
'''
result = SnowNLP(text)
for p in result.sentences:
print (p)
我不戴紧箍救不了她
戴了紧箍爱不了她
一万年太久只争朝夕
一路走来才发现没有什么是永垂不朽
我们终于懂得曾经离我们一步之遥的人
一旦错过
之后哪怕化身绝世英雄
身披金甲战衣
脚踏七彩祥云
一跃八千里
也未必追的回来
from snownlp import SnowNLP
text = '''我不戴紧箍救不了她,
戴了紧箍爱不了她。一万年太久只争朝夕,
一路走来才发现没有什么是永垂不朽。
我们终于懂得曾经离我们一步之遥的人,一旦错过,
之后哪怕化身绝世英雄,身披金甲战衣,脚踏七彩祥云,一跃八千里,也未必追的回来。
'''
result = SnowNLP(text)
artilc = ['我', '爱', '她']
print(result.sim(artilc))
[3.761200115693562, 0, 0, 0, 0, 0, 0, 0, 4.104294893075268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4.621699487939302, 0, 0, 4.104294893075268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.761200115693562, 0, 0, 0, 0, 0, 0, 0, 0, 3.761200115693562, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
from snownlp import seg
seg.train('data.txt')
seg.save('seg.marshal')
from snownlp import tag
tag.train('199801.txt')
tag.save('tag.marshal')
from snownlp import sentiment
sentiment.train('neg.txt', 'pos.txt')
sentiment.save('sentiment.marshal')
from snownlp import SnowNLP
def sentiment_analysis(data_col):
sum_score = 0 #总分初始为0
for text in data_col: #遍历表格中“优点列”和“缺点列”的文本
score = SnowNLP(text).sentiments #计算情感值
sum_score = sum_score + score #计算情感值总和
return sum_score
good_score = sentiment_analysis(data['优点'])#传入data中的优点
bad_score = sentiment_analysis(data['缺点'])
# 总分除以次数得到平均分
print ("优点情感得分为:", good_score / len(data['优点']))#范围为0-1,值越大表现越积极,否则越消极
print ("缺点情感得分为:", bad_score / len(data['缺点']))
优点情感得分为: 0.7687405426520936
缺点情感得分为: 0.30701769807858786
from wordcloud import WordCloud
from wordcloud import ImageColorGenerator
from matplotlib.image import imread
import matplotlib.pyplot as plt
import jieba.analyse
back_img = imread("./bg_pic.jpg")#读入图片
img_colors = ImageColorGenerator(back_img)#获取颜色像素值
with open("./朗逸论坛.txt", encoding="utf-8") as file:
# jieba.analyse.set_stop_words('./词典/stopword.txt') # 设置停用词列表
tags = jieba.analyse.extract_tags(file.read(), 900, withWeight=True)
data = {
item[0]: item[1] for item in tags}
word_cloud = WordCloud(font_path="c:\windows\Fonts\simhei.ttf",
background_color="white",
max_words=900,
max_font_size=100,
min_font_size=10,
width=1920,
mask=back_img,
height=1080).generate_from_frequencies(data)
word_cloud.recolor(color_func=img_colors) # 替换默认的字体颜色
file.close()
plt.figure(figsize=(16, 9)) # 创建一个图形实例
plt.imshow(word_cloud, interpolation='bilinear')
plt.axis("off") # 不显示坐标尺寸
word_cloud.to_file('./images/朗逸论坛词云.png')#保存图片
plt.show()
from snownlp import SnowNLP
from wordcloud import WordCloud
import jieba,re
#文本预处理
file = open('./朗逸论坛.txt', 'r', encoding='utf-8')
file_list = file.readline().replace('\xa0', '').replace(' ', '')#去掉符号“\xa0”和空格
text_re = re.sub('[,,??!!]+', "。", file_list)#[]中的符号都会被替换为“。”号,类似于replace()
def sentiment_analysis(text):
score = SnowNLP(text).sentiments#计算文本情感值分数
return score
text_list = text_re.split("。")#以“。”进行切分,变为数组 #建议直接使用SnowNLP(text).sentences切分句子
sum_score = 0
count = 1
for text in text_list:
if text != '':#如果文本不为空,就上到上面函数计算情感值,否则略过
score = sentiment_analysis(text)
sum_score = sum_score + score
count = count + 1
mean_score = sum_score / count #计算整篇文章情感值平均分
print ("该篇文章的情感系数为:", mean_score)
结果:
该篇文章的情感系数为: 0.5816468358548751