1.项目说明
对姓氏户籍地和工作地数据进行清洗、整合,获得姓氏的户籍城市及其经纬度,工作地城市及其经纬度。然后对数据进行分析,分析姓氏TOP20,取其中某几个姓氏分析其在全国的分布,根据户籍地与工作地的经纬度分析其奔波指数。
2.项目具体要求
1、数据清洗、整合
要求:
① 将“data01”、“data02”分别读取,并且合并成一个数据
② 结合“户籍地城市编号”及“中国城市代码对照表”数据,将城市经纬度连接进数据中
③ 分别提取“工作地”中的省、市
查看姓氏“普遍指数”,普遍指数=姓氏人口数量
要求:
① 将数据按照“姓”做统计,找到数量最多的TOP20
② 分别制作图表,查看姓氏TOP20的数量及占比
③ 选取姓氏分析在全国的分布情况,绘制密度图
查看姓氏“奔波指数”,奔波指数=姓氏人均迁徙距离。
要求:
① 根据识别的工作地,通过Geocoding查询到对应坐标
② 选择一个姓氏,计算并查看其姓氏的奔波指数,并计算该姓氏的人均通勤距离
3.实现思路:
1.数据的清洗、整合目的是获得姓氏的户籍城市及其经纬度,工作地城市及其经纬度,户籍城市及其经纬度的获取可以连接中国城市编码对照表,根据’户籍城市编号’和’行政编码’进行连接,这样就获得户籍所在地省\市\区县以及其经纬度。
工作地城市及其经纬度需要对姓氏的工作地数据使用正则表达式匹配出有效省市区地址,然后用全国省,市,区县列表循环查找是否在地址中出现,
若出现这是返回该省,市,区县名称,这里可以创建三个函数,分别用于获得省,市,区名称,使用apply()进行调用。
2.计算姓氏的人口数量,可以对清洗完成的数据根据姓氏进行分组计数,则得到每个姓氏的人数,再除以总人数则得到占比数据,
然后筛选TOP20绘制柱状图。
绘制姓氏密度图,可以使用powermap或者echarts来绘制,需要筛选出某个姓氏数据保存成excel数据,然后使用特定工具绘制
3.将筛选某个姓氏数据,将“工作地市”、“工作地区县”未识别的数据删除掉,然后将数据导出,根据工作地数据通过Geocoding查询对应坐标,
然后将数据导入到QGIS,使用插件’LinePlotter’转线,并在qgis中计算平均通勤距离,对完成转线的shapefile 文件使用在线转换工具转换成geojson格式数据,
接着使用geojson格式数据作为echarts绘图的数据绘制轨迹图。
4.实现过程:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
# 不发出警告
from bokeh.io import output_notebook
output_notebook()
# 导入notebook绘图模块
from bokeh.plotting import figure,show
from bokeh.models import ColumnDataSource
# 导入图表绘制、图标展示模块
# 导入ColumnDataSource模块
import os
os.chdir(r'D:\IT\python数据分析师\项目9')
#读取数据
df1 = pd.read_csv('data01.csv',encoding = "utf-8")
df2 = pd.read_csv('data02.csv',encoding = 'utf-8')
df_xzdm = pd.read_excel('中国行政代码对照表.xlsx')
df_all = pd.concat([df1,df2]) # '户籍地城市编号'数据连接
#连接“户籍地城市编号”及“中国城市代码对照表”数据,
data = pd.merge(df_all,df_xzdm,left_on ='户籍地城市编号',right_on='行政编码',how='inner')
#筛选列,更改列名
data = data[['姓','工作地','省','市','区/县','lng','lat']]
data.columns = ['姓','工作地','户籍所在地_省','户籍所在地_市','户籍所在地_区/县','户籍所在地_lng','户籍所在地_lat']
#城市代码对照表数据中筛选出'省','市','区/县',得到adr_data
adr_data = df_xzdm[['省','市','区/县']]
#删除adr_data中'市','区/县'两列中信息相同的行
for i in adr_data.index.tolist():
if adr_data['市'][i] in adr_data['区/县'][i]:
adr_data.drop(i,inplace = True)
p_lst = adr_data['省'].unique().tolist() #'省'名称list
c_lst = adr_data['市'].unique().tolist()#'市'名称list
a_lst = adr_data['区/县'].unique().tolist() #'区/县'名称list
a_lst.remove('城区')
a_lst.append('城区') #将'城区'转移到'区/县'list末尾
#创建函数在'省'list中匹配信息,匹配到则返回匹配到的省份信息
def province(s):
for i in p_lst:
if i[:2] in s:
return i
#创建函数在'市'list中匹配信息,匹配到则返回匹配到的市名信息
def city(s):
for i in c_lst:
if i[:2] in s:
return i
#创建函数在'区/县'list中匹配信息,匹配到则返回匹配到的区/县信息
def area(s):
for i in a_lst:
if i in s:
return i
#利用正则表达式匹配地址信息中的省,市,区/县信息并返回,移除掉乡镇,街道信息
import re
def f(s):
m = re.match('.*[区|县]|.*市',s)
if m != None:
return m[0]
else:
return ''
#创建工作地_省,工作地_市,工作地_区县 三列
data['工作地_2'] = data['工作地'].apply(lambda s:f(s))
data['工作地_省'] =data['工作地_2']
data['工作地_市'] = data['工作地_2']
data['工作地_区/县'] = data['工作地_2']
#利用函数匹配出地址中的省份名,市名,区县名
data['工作地_省'] = data['工作地_省'].apply(lambda x:province(x))
data['工作地_市'] = data['工作地_市'].apply(lambda x:city(x))
data['工作地_区/县']= data['工作地_区/县'].apply(lambda x:area(x))
data.drop('工作地_2',axis = 1,inplace = True)
#工作地信息无法提取则填充为'未识别'
data.fillna('未识别',inplace = True)
说明:
数据清洗和整合中,获取户籍所在地地址和经纬度比较简单,根据“户籍地城市编号”连接“中国城市代码对照表”即可,难点是对因此可以先使用正则表达式匹配获得地址省/市/区县主要信息,然后与省名称列表,市名称列表,区县名称列表进行循环查找,若地址中包含有省/市/区县名称,则获得该名称,若未查找到则返回’未识别’。在这里创建三个函数分别获取省/市/区县名称。
#查看姓氏“普遍指数”,普遍指数=姓氏人口数量
#要求:
#① 将数据按照“姓”做统计,找到数量最多的TOP20
#② 分别制作图表,查看姓氏TOP20的数量及占比
from bokeh.layouts import gridplot
from bokeh.models import HoverTool
xs_g = data.groupby('姓').count()[['工作地']].sort_values(by = '工作地',ascending = False) #by姓氏分组的到每个姓氏的数量
xs_g.columns =['quantity'] #更改列名
xs_top = xs_g.iloc[:20] #筛选出数量 TOP20的姓氏
xs_top['propotion'] = xs_top['quantity']/xs_top['quantity'].sum() #计算并添加占比字段
xs_top.index.name = 'surname' #重命名索引
name_lst = xs_top.index.tolist() #TOP20 姓氏列表
#创建source
source = ColumnDataSource(data= xs_top)
#第一个图表的标签设置
hover1 = HoverTool(tooltips = [('姓氏计数:','@quantity')])
#创建第一个图表对象
p1 = figure(x_range = name_lst,plot_width = 800,plot_height = 300,title = '中国姓氏TOP20-计数',
tools = [hover1,'wheel_zoom,reset'],toolbar_location = 'above')
#绘制数量柱状图
p1.vbar(x = 'surname',top = 'quantity',source = source,width = 0.8,color = 'skyblue',alpha = 0.7)
p1.grid.grid_line_dash = [10,4]
#第二个图表的标签设置
hover2 = HoverTool(tooltips = [('姓氏占比:','@propotion')])
#创建第二个图表对象
p2 = figure(x_range = p1.x_range,plot_width = 800,plot_height = 300,title = '中国姓氏TOP20-占比',
tools = [hover1,'wheel_zoom,reset'])
#绘占比制柱状图
p2.vbar(x = 'surname',top = 'propotion',source = source,width = 0.8,color = 'olive',alpha = 0.7)
p2.grid.grid_line_dash = [10,4]
#创建联动图表
p = gridplot([p1],[p2])
show(p)
说明:
1.根据姓氏进行分组计数得到各个姓氏的人数,排序后选取TOP20,使用bokeh绘制计数柱状图和占比柱状图。
2.根据图表可知人数最多的几个姓氏是’王’,’张’,’李’,’刘’,’陈’
#查看“王”姓的全国分布
#查看“姬”姓的全国分布
#创建函数传入数据和姓氏,获得相应姓氏的数据
def name_count(data,surname):
name = data.loc[data['姓'] ==surname,['姓','户籍所在地_lng','户籍所在地_lat']]
n_count = name.groupby(['户籍所在地_lng','户籍所在地_lat']).count().reset_index()
n_count.rename(columns ={'姓':'value'},inplace = True)
n_count.insert(0,'name',surname)
n_count.to_csv('%s性分布.csv' % s)
#获取'王','姬'姓氏的数据
wang = name_count(data,'王')
ji = name_count(data,'姬')
说明:
1.获得某个姓氏的户籍所在地经纬度数据可以创建一个函数,筛选处理数据,并保存成csv格式数据。
2.分析在全国的分布状况,使用powermap和echarts,powermap是office2016中excel的一个分析工具,使用方便,echarts是一款基于HTML5的图形库,需要自行设置多种参数,相对复杂,但是功能强大丰富,使用灵活。
3.这里分析的’姬’姓和’王’姓的全国分布可知’姬’姓人数较少,主要分布在北方,大部分集中在河南郑州附近。
4.’王’姓人数多,分布广,在全国各地都有分布,主要集中在东部地区,其中北京地区人数最为集中,中部分布相对较少。
5.西部地区和南方地区分布很少。
#创建函数导出某一个姓氏的数据用于计算该姓氏的奔波指数
def surname_tocsv(data,s):
surname_data = data[['姓','户籍所在地_lng','户籍所在地_lat','工作地_市','工作地_区/县']][data['姓']==s]
surname_data = surname_data.loc[(surname_data['工作地_市']!='未识别')&(surname_data['工作地_区/县']!='未识别'),:]
surname_data.to_csv('%s.csv' % s)
surname_tocsv(data,'汤')
说明:
1.对奔波指数的数据可视化最后使用空间轨迹图开展示人员的迁徙和移动,这里使用 echarts来绘图,因此需要获得goejson格式数据,获得数据的途径就是使用QGIS根据户籍所在地经纬度以及工作地所在地经纬度数据进行转线处理得到shapefile,然后将shapefile转换成goejson数据。
2.这里对’汤’姓计算器奔波指数并绘制奔波轨迹图,根据轨迹图可知,迁徙方向主要是北上广深和各大主要省会城市。
5.总结
- 该项目主要是对空间数据的分析,需要使用各种空间数据分析及可视化的工具对人口分布及迁徙数据进行分析并进行可视化。
- 通过该项目的完成对如何使用各种空间分析和可视化工具完成实际问题有了一个全面的了解,特别是绘制迁徙轨迹图,
- 从获取数据,计算数据,转换数据,设置echarts到最后呈现有个一个完整的思路。
- 该项目的对于工作地的数据清洗是较为复杂的,需要自行设计算法函数来实现,清洗处理复杂数据能力有很到的提高。