项目介绍
本项目结合 matplotlib 可视化来做分析,以直观的方式展示各大城市从2015到2017年的变化情况,并加与文字说明。
目标定义
目标需求分析1:对比2015至2017年主要城市年度数据的变化趋势。
目标需求分析2:对比各个城市在这几年的国内生产总值情况,哪些城市贡献大?
目标需求分析3:对比各个城市第一、二、三产业在这几年的发展状况是怎样的?
目标需求分析4:对比各个城市平均在职工资、学校资源、卫生医院设备情况,看看哪些城市工资高、教学资源丰富、医疗保障水平是怎样的?
目标需求分析5:对比分析哪些城市是房地产投资重地呢?
实践流程
1 加载合并数据
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
df1 = pd.read_csv('/govstats2556/2015年国内主要城市年度数据.csv')
df2 = pd.read_csv('/govstats2556/2016年国内主要城市年度数据.csv')
df3 = pd.read_csv('/govstats2556/2017年国内主要城市年度数据.csv')
df = pd.concat([df1, df2, df3], axis=0) # 以行的维度合并数据
print('\n【特征】>>>', df.columns)
# 重置索引和特征名
df.index = [i for i in range(df.shape[0])] # 重置索引
df.columns = ['area', 'year', 'total_value', 'one_value', 'two_value',
'three_value','zero_value', 'inout', 'population', 'pay',
'student', 'hospitalt', 'realty'] # 重置列名
df.info() # 查看数据集基本情况
df.head()
英文 | 中文 |
---|---|
area | 地区 |
year | 年份 |
total_value | 国内生产总值 |
one_value | 第一产业增加值 |
twol_value | 第二产业增加值 |
three_value | 第三产业增加值 |
zero_value | 社会商品零售总额 |
inout | 货物进出口总额 |
population | 年末总人口 |
pay | 在岗职工平均工资 |
student | 普通高等学校在校学生数 |
hospital | 医院、卫生院数 |
realty | 房地产开发投资额 |
2 数据预处理
# 探索是否有缺失值
print('\n缺失值处理前>>>', df.isnull().sum(), '\n>>>', df.shape)
# 缺失值处理
''' 第一种方法,丢弃 '''
# df = df.dropna()
''' 第二种方法,使用均值填充 '''
# df = df.fillna(value=df.mean())
# 由于我们发现缺失值只在 "realty" 列,因此可以使用以下方式
df['realty'] = df['realty'].fillna(value=df['realty'].mean())
print('\n缺失值处理后>>>', df.isnull().sum(), '\n>>>', df.shape)
3 封装可视化模板和可视化分析
def plotCity(data, plotType=None):
# 设置图像风格, 网格型
plt.style.use('ggplot')
# 解决中文乱码,坐标轴显示不出负值的问题
plt.rcParams['font.sans-serif'] =['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 提取各年份的数据
dt2015 = df[df['year'] == 2015]
dt2016 = df[df['year'] == 2016]
dt2017 = df[df['year'] == 2017]
# 可视化图像的标题
plot_title = ['国内生产总值', '第一产业增加值', '第二产业增加值',
'第三产业增加值', '社会商品零售总额', '货物进出口总额',
'在岗职工平均工资', '普通高等学校在校学生数', '医院、卫生院数',
'房地产开发投资额']
# ------------------------------------------------
# 4-1、在没有指明绘制图形类型情况下,采用默认方式
if plotType == None:
text = print("""温馨提示:你还没有选择绘制图形的类型.....\n类型如下...
plot\t线性图
pie\t饼图
bar\t纵向条形图
barh\t横向条形图
hist\t直方图
boxplot\t箱型图
scatter\t散点图
\n例子\n---------"""
+ "\nplot(data=data, plotType='plot')")
return text
fig = plt.figure()
for i in range(0, len(data) - 1):
# for i in range(0, 4):
ax = fig.add_subplot(5, 2, i + 1)
# --------------------------------------------------
# 4-2、选择绘制线形图
if plotType == 'plot':
ax.plot(dt2015[data[0]], dt2015[data[i + 1]], marker='o', label='2015')
ax.plot(dt2016[data[0]], dt2016[data[i + 1]], marker='o', label='2016')
ax.plot(dt2017[data[0]], dt2017[data[i + 1]], marker='o', label='2017')
ax.set_title(plot_title[i]) # 标题
ax.set_xticklabels(labels=dt2015[data[0]], rotation=90) # 设置 X 轴刻度对应的标签
ax.legend(loc='best') # 图例
fig.subplots_adjust(top=5, bottom=0.1, left=0.9, right= 3.6,
hspace=0.3, wspace=0.3) # 调整子图之间间隙
# --------------------------------------------------
# 4-3、选择绘制饼图
if plotType == 'pie':
ax.pie(x=dt2015[data[i + 1]], labels=dt2015[data[0]], shadow=True,
autopct='%.2f%%', radius=2.)
ax.set_title(plot_title[i]) # 标题
# ax.legend(loc='right') # 图例
# 调整子图间距,上下左右
fig.subplots_adjust(top=5, bottom=0.1, left=0.9, right= 3.6,
hspace=0.8, wspace=0.1)
# ---------------------------------------------------
# 4-4、选择绘制纵向条形图
if plotType == 'bar':
bar_width = 0.3
''' 正 y 轴绘制条形图 '''
ax.bar(x=dt2015.index, height= + dt2015[data[i + 1]], # 正 y 半轴绘图
label='正轴2015', width=bar_width)
ax.bar(x=dt2015.index + bar_width, height= + dt2016[data[i + 1]], # 正 y 半轴绘图
label='正轴2016', width=bar_width)
ax.bar(x=dt2015.index + 2 * bar_width, height= + dt2017[data[i + 1]], # 正 y 半轴绘图
label='正轴2017', width=bar_width, color='y')
''' 负 y 轴绘制条形图 '''
ax.bar(x=dt2015.index, height= - dt2015[data[i + 1]], # 负 y 半轴绘图
label='负轴2015', width=bar_width, color='r')
ax.bar(x=dt2015.index + bar_width, height= - dt2016[data[i + 1]], # 负 y 半轴绘图
label='负轴2016', width=bar_width, color='c')
ax.bar(x=dt2015.index + 2 * bar_width, height= - dt2017[data[i + 1]], # 负 y 半轴绘图
label='负轴2017', width=bar_width, color='b')
ax.set_title(plot_title[i]) # 标题
ax.set_xticks([i for i in range(dt2015.shape[0])]) # 重置 x 轴刻度值
ax.set_xticklabels(labels=dt2015[data[0]], rotation=90) # 在 x 轴刻度值上设置标签,旋转 90 度
ax.legend(loc='best') # 图例,自动选择最好的位置摆放图例
# 调整子图间距,上下左右
fig.subplots_adjust(top=5, bottom=0.1, left=0.9, right= 3.6,
hspace=0.3, wspace=0.3)
# ---------------------------------------------------
# 4-5、选择绘制横向条形图
if plotType == 'barh':
ax.barh(y= + dt2015.index, width= dt2015[data[i + 1]], height=2,
label='2015') # 正 x 半轴绘图
ax.barh(y= - dt2015.index, width= dt2016[data[i + 1]], height=2,
label='2016') # 负 x 半轴绘图
ax.set_title(plot_title[i]) # 标题
ax.set_yticks([i for i in range(dt2015.shape[0])] +
[-i for i in range(dt2015.shape[0])]) # 重置 y 轴刻度值
ax.set_yticklabels(labels=dt2015[data[0]].tolist() +
dt2015[data[0]].tolist()) # 在 y 轴刻度值上设置标签
ax.legend(loc='best')
# 调整子图间距,上下左右
fig.subplots_adjust(top=18, bottom=0.1, left=0.9, right= 3.6,
hspace=0.3, wspace=0.3)
# ------------------------------------------------------
# 4-6、选择绘制直方图
color = ['r', 'g', 'c', 'b', 'm', 'r', 'g', 'c', 'b', 'm']
if plotType == 'hist':
ax.hist(x= -dt2015[data[i + 1]], bins=10, color=color[i], label='2015') # 正 x 半轴绘图
ax.hist(x= dt2016[data[i + 1]], bins=10, color=color[-(i + 1)], label='2016')
ax.legend(loc='best') # 图例
ax.set_title(plot_title[i]) # 标题
# 图像文本设置
ax.text(x=0, y=4, s='LXZ说:直方图用于探索各个元素出现的频次', fontsize=14, color='k')
# 调整子图间距,上下左右
fig.subplots_adjust(top=5, bottom=0.1, left=0.9, right= 3.6,
hspace=0.3, wspace=0.3)
# -------------------------------------------------------
# 4-7、选择绘制箱形图
if plotType == 'boxplot':
# patch_artist=True 填充颜色
ax.boxplot(x=[dt2015[data[i + 1]], dt2016[data[i + 1]],
dt2017[data[i + 1]]], patch_artist=True)
ax.set(title=plot_title[i],
ylabel='元素值分布',
xlabel='年份',
xticklabels=(['2015', '2016', '2017']))
# 设置箭头标注,s 代表要显示的文字,xy 代表箭头的位置,xytext 代表文字
# 的位置,arrowprops 代表设置箭头的样式
ax.annotate(s='中位数:' + str(dt2016[data[i + 1]].median()), xy=(2, dt2016[data[i + 1]].median()),
xytext=(2.25, dt2016[data[i + 1]].median() + 50), fontsize=20, color='k',
arrowprops=dict(arrowstyle="->",connectionstyle='arc3',color='r',))
ax.grid(True) # 添加网格
# 子图间隙调整
fig.subplots_adjust(top=5, bottom=0.1, left=0.9, right= 3.6,
hspace=0.3, wspace=0.3)
测试
data = ['area', 'total_value', 'one_value', 'two_value',
'three_value','zero_value', 'inout', 'pay',
'student', 'hospitalt', 'realty']
plotCity(data)
data = ['area', 'total_value', 'one_value', 'two_value',
'three_value','zero_value', 'inout', 'pay',
'student', 'hospitalt', 'realty']
plotCity(data=data, plotType='plot')
第一、二、三产业百度百科介绍如下:
- 第一产业指生产食材以及其它一些生物材料的产业,如:种植业、林业、畜牧业、水产养殖业等直接以自然物为生产对象的产业。
- 第二产业主要指加工制造产业,利用自然界和第一产业提供的基本材料进行加工处理。
- 第三产业是指第一、第二产业以外的其他行业,主要包括交通运输业、通讯产业、商业、餐饮业、金融业、教育产业、公共服务等非物质生产部门。
由上面的线形图可视化可分析如下:
总体来看
- 各个省份的各项指标总体来说,呈现逐年增加的态势,不过增加的幅度不是很大
各项指标
在国内生产总值指标中
- 北上广深、重庆占据绝对优势
- 太原、呼和浩特、海口、西宁倒数,占比最小
在第一、二、三产业指标中
- 重庆是第一、第二产业龙头
- 北上广深是第二、三产业龙头
在零售总额指标中
- 北上广深、重庆不负众望,仍然占据绝对优势
在货物进出口指标中
- 北上深以绝对的优势碾压各省
- 其他省份普遍较低
在平均工资指标中
- 北上广深,拉萨占比较大
在校学生数指标中
- 宁夏、厦门、深圳、海口、拉萨、西宁、银川占比最小
- 深圳虽然是一线城市,但是大学学校不多
在医院数指标中
- 重庆、成都占比较大
在房地产投资指标中
- 北京、上海、杭州、郑州、广州、重庆、西安占比较大
综上所述
- 发展比较好的城市:北上广深、重庆
- 发展比较落后的城市:太原、呼和浩特、海口、西宁
data = ['area', 'total_value', 'one_value', 'two_value',
'three_value','zero_value', 'inout', 'pay',
'student', 'hospitalt', 'realty']
plotCity(data=data, plotType='pie')
data = ['area', 'total_value', 'one_value', 'two_value',
'three_value','zero_value', 'inout', 'pay',
'student', 'hospitalt', 'realty']
plotCity(data=data, plotType='bar')
data = ['area', 'total_value', 'one_value', 'two_value',
'three_value','zero_value', 'inout', 'pay',
'student', 'hospitalt', 'realty']
plotCity(data=data, plotType='barh')
data = ['area', 'total_value', 'one_value', 'two_value',
'three_value','zero_value', 'inout', 'pay',
'student', 'hospitalt', 'realty']
plotCity(data=data, plotType='hist')
data = ['area', 'total_value', 'one_value', 'two_value',
'three_value','zero_value', 'inout', 'pay',
'student', 'hospitalt', 'realty']
plotCity(data=data, plotType='boxplot')
雷达图可视化探索
下面将以雷达图来探索 36 个省 2015、2016、2017年的变化情况
探索指定的特征三年来的变化
第二产业增加值
年末总人口
房地产开发投资额
批量绘制 36 个雷达图…
# 将'year'设置成索引列
df = df.set_index(keys='year')
import numpy as np
def leida(city):
# 正常显示中文、坐标轴负号的问题
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
fig = plt.figure() # 设置画布
plt.style.use('ggplot') # 图像风格
# 特征的标签
labels = ['第二产业增加值', '年末总人口', '房地产开发投资额']
for i in range(len(city)):
# 各省数据
# beijing = df[df['area'] == '北京']
values1 = df[df['area'] == city[i]].iloc[0, [3, 7, 11]].tolist() # 2015 年
values2 = df[df['area'] == city[i]].iloc[1, [3, 7, 11]].tolist() # 2016 年
values3 = df[df['area'] == city[i]].iloc[2, [3, 7, 11]].tolist() # 2017 年
# print(values1, values2)
# 分配角度
angles = np.linspace(0, 2 * np.pi, len(values1), endpoint=False)
# 将数据和角度连接成一个圆圈
values1 = np.concatenate((values1, [values1[0]]))
values2 = np.concatenate((values2, [values2[0]]))
values3 = np.concatenate((values3, [values3[0]]))
angles = np.concatenate((angles, [angles[0]]))
# 36 个省,绘制 18 x 2 个子图
ax = fig.add_subplot(18, 2, i + 1, polar=True) # polar=True 代表绘制极坐标图
'''
绘制雷达图:
marker='o' 代表设置点的样式为"圆圈"
linewidth 线条的宽度
label 标签,与图例共同使用
'''
ax.plot(angles, values1, marker='v', color= 'r', linewidth=1.5, label='2015')
ax.fill(angles, values1, alpha=0.25)
ax.plot(angles, values2, marker='v', color= 'm', linewidth=1.5, label='2016')
ax.fill(angles, values2, alpha=0.25)
ax.plot(angles, values3, marker='o', color= 'c', linewidth=1.5, label='2017')
ax.fill(angles, values3, alpha=0.25)
ax.set_thetagrids(angles * 180 / np.pi, labels) # 标注上特征标签
ax.set_title(city[i]) # 设置标题
plt.legend(loc='center left') # 图例, 左边中部
ax.grid(True) # 添加网格
# 子图间隙调整,top 主要控制子图高度,right 主要控制子图宽度,
# left 调整子图之间左右的间隙,bottom 调整上下间隙
# fig.subplots_adjust(top=30, right=15, left=9) # 左右间隙过大
# fig.subplots_adjust(top=30, right=15, left=14) # 上下间隙过大
fig.subplots_adjust(top=30, right=15, left=14, bottom=17)
# ----------------------------------------
# 测试调用雷达图
# tolist() 代表转换成列表
city = df['area'][:36].tolist()
leida(city)