菜鳥筆記Python3——數據可視化(二)世界地圖

參考教材

<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: 總結

其實還是有沒有統計進去的,但是臣妾已經盡力了,如果在提取關鍵詞的時候多提取幾個應該就可以把更多的地區統計進來

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容