参考教材
<Python编程——从入门到实践> chapter16 数据可视化
引言
在第二小节里面,我们学习并绘制了一张世界人口分布图,但是在提取相关数据时,我们发现,由于格式不规范,原始数据中的很多地区并没有相应的国别码,在这个练习中,我们需要尽量改善这个问题......
原题
本节制作人口地图时,对于大约12个国家,程序不能自动确定其两个字母的国别码,请找出这些古欧家,在字典 COUNTRIES 中找到他们的国别码,然后对于每个这样的国家,都在原代码中添加一个if-elif代码块,用于返回其国别码
开始!
啧啧啧,才12个国家,手工添加也不是很多嘛!但是,根据上一节被坑的经验,我们还是来看一看到底找不到国别码的地区有多少个好了
先小小地修改一下代码, 把有问题的地区先存到列表 err_country 中
for pop_dict in pop_data:
if pop_dict['Year'] == '2010':
country_name = pop_dict['Country Name']
population = int(float(pop_dict['Value']))
code = get_country_code(country_name)
if code:
cc_population[code] = population
if code == None:
err_country.append(country_name)
err_pop.append(population)
print(err_country)
看一看结果:
(ノ=Д=)ノ┻━┻ 这么多的问题地区是什么情况!!!!
好吧,事已至此,我们想想怎么用代码解决这个问题
先观察一下这个 err_country 列表
我们发现在 'World' 这个词之前,都是一些一眼就能看出不是国家的元素
先把它们全都删掉再说!
先贴代码:
err_pop = []
key = True
for pop_dict in pop_data:
if pop_dict['Year'] == '2010':
country_name = pop_dict['Country Name']
population = int(float(pop_dict['Value']))
code = get_country_code(country_name)
if code:
cc_population[code] = population
if (code == None) and (key == False):
err_country.append(country_name)
err_pop.append(population)
if country_name == 'World':
key = False
用一个 key 来检测是否读取到了 'World',只有在 'World‘ 之后的元素才被存进 列表 err_country 中,同时, 我们用一个列表 err_pop 来储存对应的人口信息
运行一下:
很好!前面那些太明显的地名已经没了
在 COUNTRIES 字典中找到对应的国别码
虽然剔除了很多信息,但是剩下的地名依然很多,还是要依靠代码找到他们对应的国别码
分析一下
程序之所以找不到这些地名对应的国别码,是因为它们的名字跟字典 COUNTRIES 里的标准名称不匹配,要解决这个问题,一个简单的思路是 我们只提取 这些地名的部分单词作为关键字,然后用这些关键字去跟字典 COUNTRIES 进行匹配, 可以观察到,大部分的地名的关键字都在 第一个单词,少数以 'St.' 开头的地名 关键字在 'St.' 后的第一个单词
这样,大致的思路就出来了
思路:提取关键字-> 匹配字典->加上人口信息做成新的字典
step 1: 关键字的提取
很简单,对于每一个 'err_country' 里的字符串元素,从第个字符开始查找点号 '.', 空格 ' ' ,还有逗号 ',',一旦找到就停下来,把之前的字符存在新的字符串中,可以用两个循环实现,我们把这个功能做成一个函数:
def get_first_word(name):
new_name = ''
for letter in name:
new_name += letter
if letter == ','or letter == ' ' or letter == '.':
new_name = new_name[:-1] #删掉最后的 , 空格 或者 .
break
return new_name
step 2: 匹配字典
一样依靠两个循环实现,这里比较麻烦的是要把储存人口数据的 'err_pop' 里面的数据 对应地 放到新字典里面,本人没什么好方法,用了最笨的计数法,在历遍 err_country 的同时, 用 count 控制 err_pop 保持同步
def get_pop(filename):
--snip--
new_country = {}
count = -1
for err_country in new_err:
count += 1
for code , country in COUNTRIES.items():
if err_country in country:
new_country[code] = err_pop[count]
--snip--
step 3:合成一个新的字典
这一步算是最简单的了,不废话,直接上
for code, pop in new_country.items():
cc_population[code] = pop
完整的代码在这里
#! /usr/bin/python <br> # -*- coding: utf8 -*-
import json
from country_codes import get_country_code
import string as s
from pygal.maps.world import COUNTRIES
def get_first_word(name):
new_name = ''
for letter in name:
new_name += letter
if letter == ','or letter == ' ' or letter == '.':
new_name = new_name[:-1] #删掉最后的 , 空格 或者 .
break
return new_name
def get_pop(filename):
filename = 'population_data.json'
cc_population = {}
err_country = []
with open(filename) as f:
pop_data = json.load(f)
err_pop = []
key = True
for pop_dict in pop_data:
if pop_dict['Year'] == '2010':
country_name = pop_dict['Country Name']
population = int(float(pop_dict['Value']))
code = get_country_code(country_name)
if code:
cc_population[code] = population
if (code == None) and (key == False):
err_country.append(country_name)
err_pop.append(population)
if country_name == 'World':
key = False
print(err_country)
new_err = []
for country_name in err_country:
new_name = get_first_word(country_name)
if new_name == 'St':
new_name = country_name[4:]
new_name = get_first_word(new_name)
new_err.append(new_name)
new_country = {}
count = -1
for err_country in new_err:
count += 1
for code , country in COUNTRIES.items():
if err_country in country:
new_country[code] = err_pop[count]
for code, pop in new_country.items():
cc_population[code] = pop
return cc_population
然后绘图文件那里也要做相应的修改,很简单,直接贴完整的代码好了
#! /usr/bin/python <br> # -*- coding: utf8 -*-
import pygal
import json
from country_codes import get_country_code
from pygal.style import RotateStyle
from pygal.style import LightColorizedStyle
from countries import get_pop
#将数据加载到一个列表中
filename = 'population_data.json'
#创建一个包含人口数量的字典
cc_population = {}
cc_pop1,cc_pop2,cc_pop3 = {},{},{}
cc_population = get_pop(filename)
for cc,pop in cc_population.items():
if pop < 10000000:
cc_pop1[cc] = pop
elif pop < 1000000000:
cc_pop2[cc] = pop
else:
cc_pop3[cc] = pop
wm_style = RotateStyle('#226699',base_style=LightColorizedStyle)
wm = pygal.maps.world.World(style=wm_style)
wm.title = 'World Population in 2010, by Country'
wm.add('0-10m',cc_pop1)
wm.add('10m-1bn',cc_pop2)
wm.add('>1bn',cc_pop3)
wm.render_to_file('world_population_v10.svg')
上一张成果图
比较一下之前的
给自己鼓个掌!!!!!!
PS: 总结
其实还是有没有统计进去的,但是臣妾已经尽力了,如果在提取关键词的时候多提取几个应该就可以把更多的地区统计进来
网友评论