设置画板
import warnings
import matplotlib.pyplot as plt
%matplotlib inline
# 屏蔽代码运行过程中出现的警告信息,主要是屏蔽 pandas 的 .loc 警告问题
warnings.filterwarnings("ignore")
fontsize = 20
plt.rcParams['xtick.labelsize'] = fontsize
plt.rcParams['ytick.labelsize'] = fontsize
plt.rcParams['axes.labelsize'] = fontsize
plt.rcParams['axes.titlesize'] = fontsize
plt.rcParams['legend.fontsize'] = fontsize
plt.rcParams['legend.frameon'] = False # 去除图例边框
plt.rcParams['axes.unicode_minus'] = False # 显示负数
plt.rcParams['axes.spines.right'] = False # 去除右侧坐标轴
plt.rcParams['axes.spines.top'] = False # 去除顶部坐标轴
数据准备
#数据导入
import pandas as pd
df = pd.read_csv('https://labfile.oss.aliyuncs.com/courses/3023/American_Race_Gender_Population.csv')
df.head()
#认识数据:本数据集来源于美国人口普查局与美国国家卫生统计中心,该数据集统计了美国自 1990 至 2019 年期间,各年度全美 51 州各年度性别(Gender)、种族(Race)、年龄段(Age Group)的人口数(Population),数据集中的 Mean Age 字段根据 Age Group 求算术平均得到。
各州各种族人口数分布
目标:想做一个在不同州不同种族上人口数的散点图分布。步骤:
- 将数据集按照州(State)、种族(Race)进行人口数(Population)聚合并按照人口数升序排序。
- 聚合后,将聚合数据集中的 State、Race 特征分别映射至散点图 x、y 坐标,将 Population 人口数特征映射至点的颜色(c)和大小(s)。
- 还有年份这一特征,选择最大最小两个年份(1990 和 2019 )作图。
plt.rcParams['figure.figsize'] = (20, 5)
for year in [1990, 2019]:
data = df.loc[df['Year'] == year]
# 各州按照总人口数升序排序
state_order = data.groupby(['State'])[
'Population'].sum().sort_values().index
# 将 State 字段设置为有序字段,astype:转换数组的数据类型。
data['State'] = data['State'].astype(
pd.api.types.CategoricalDtype(state_order, ordered=True))
# 获取州、种族的聚合结果,并按州升序排序
data = data.groupby(['State', 'Race'], as_index=False)[
'Population'].sum().sort_values(['State'])
plt.scatter(
x=data['State'],
y=data['Race'],
c=data['Population'],
s=data['Population']*0.0001,
ec='tab:blue',
cmap=plt.cm.Accent,
alpha=0.8)
#c指colors颜色,s表示点的大小,cmap指定某个colormap值
#plt.gca可以通过这个改图标的边框属性
ax = plt.gca()
# 将x轴刻度标签旋转90度,刻度字太多
ax.tick_params(axis='x', rotation=90)
# 调节y轴显示范围
ax.set_ylim(-0.5, 3.5)
plt.title('Population Distribution of States of American in Year %d' % year)
plt.show() # 关闭当前图层以绘制下一幅图
做出图了最好给出一些结论。
例如,州对比:在2019年,人口数最多的州是哪些,最少的州是哪些。
种族对比:不同种类的人口数是怎么排名的
各州人口变迁:1990年与2019年,有哪些变化趋势
人口与人口增长率
通过数据透视计算1990到2019的各州人口增长率(Pupulation Changed %),通过数据聚合计算各州 2019 年总人口数(Population)
data = df.loc[(df['Year'] == 1990) | (df['Year'] == 2019)]
# 计算美国各州人口增长率
#pivot_table数据透视表,可以查询每个参数含义
pop_change = data.pivot_table(
index='State', columns='Year', values='Population',aggfunc='sum')
pop_change['Population Changed/%'] = 100 * \
(pop_change[2019]-pop_change[1990])/pop_change[1990]
pop_change
# 计算美国2019年各州总人口数
pop = df.loc[df['Year'] == 2019].groupby(['State'])['Population'].sum()
# # 将人口总数与人口增长率数据合并并筛选需要的特征
data = pd.concat([pop, pop_change], axis=1)[
['Population', 'Pupulation Changed/%']]
data.head()
将人口总数与人口增长率数据分别映射到散点图 x、y 坐标及点颜色和大小
plt.rcParams['figure.figsize'] = (14, 7)
x = data['Population']
y = data['Pupulation Changed/%']
#散点图plt.scatter中,marker表示点的形状,s表示点的大小,
#c表示颜色,cmap指定某个colormap值(颜色图),alpha指透明度
plt.scatter(x, y,
marker='o',
s=data['Population']*0.0001,
c=data['Population'],
cmap=plt.cm.Blues_r,
edgecolors='gray') # 散点图标记的轮廓及填充颜色
plt.xlabel('Population')
plt.ylabel('Pupulation Changed /%')
#axhline()函数用于绘制平行于x轴的水平参考线.y是水平参考线的出发点
plt.axhline(y=y.mean(),color='tab:red',label='Avg Changed Ratio: %.2f%%'%(y.mean()))
#写成图例
plt.legend()
s = data.index
#plt.text给每个点加标签。
#对plt.text(x, y, s, fontsize, verticalalignment,horizontalalignment,rotation , **kwargs)
#x,y表示标签添加的位置。s表示标签的符号,字符串格式。fontsize顾名思义就是你加标签字体大小了,取整数。verticalalignment表示垂直对齐方式 ,horizontalalignment表示水平对齐方式 ,可以填 ‘center’ , ‘right’ ,‘left’ 等。rotation表示标签的旋转角度,以逆时针计算,取整
for xpos, ypos, text in zip(x, y, s):
plt.text(xpos, ypos, text, size=16,va='bottom',ha='left')
plt.title('Population & Pupulation Changed (Compared to Year 1990) of American')
依旧根据图形写成分析结果:
例如,平均增长率y.mean(),对于各个州,哪些达到了平均增长率,哪些州没有。增长率最大/小的州是哪些
对于人口数量较少和人口增速不明显的多数州,其数据被压缩至平均线以下的 0 轴附近,可通过将数据进行对数变换(log)的方法,将数据均匀分布。
##x,y数值取np.log 对数,其他步骤和上面一样。
import numpy as np
plt.rcParams['figure.figsize'] = (14, 7)
x = np.log(data['Population'])
y = np.log(data['Pupulation Changed/%'])
plt.scatter(x, y,
marker='o',
s=data['Population']*0.0001,
c=data['Population'],
cmap=plt.cm.Blues,
label='Changed of States of American',
edgecolors='gray') # 散点图标记的轮廓及填充颜色
plt.xlabel('log (Population)')
plt.ylabel('log (Pupulation Changed /%)')
s = data.index
for xpos, ypos, text in zip(x, y, s):
plt.text(xpos, ypos, text, size=16, va='bottom', ha='left')
plt.title('Population & Pupulation Changed (Compared to Year 1990) of American')
数据在对数坐标系下,分散变得十分均匀,各数据点被均匀拉开。下次作图时数据现实集中时,考虑取对数。
种族及人口变化率
白人
在前面图示中,人口中白人占据了极大部分。所以计算各州人口增长率与白人增长率。
和上面的计算增长率的代码相似
data = df.loc[(df['Year'] == 1990) |(df['Year'] == 2019) ]
# 计算美国各州人口增长率
pop_change=data.pivot_table(index='State',columns='Year',values='Population',aggfunc='sum')
pop_change['Pupulation Changed/%']=100*(pop_change[2019]-pop_change[1990])/pop_change[1990]
pop_change
# 计算美国各州白人人口增长率
white_change=data.loc[data['Race']=='White'].pivot_table(index='State',columns='Year',values='Population',aggfunc='sum')
white_change['White Changed/%']=100*(white_change[2019]-white_change[1990])/white_change[1990]
white_change
# 将人口增长率与白人增长率数据合并
changed=pd.concat([pop_change,white_change],axis=1)
# 挑选主要字段
changed=changed[['Pupulation Changed/%','White Changed/%']]
# 展示前5行数据
changed.head()
得到各州总人口增长率和白人增长率后,比较一下增长率情况。将各州人口增长率与各州白人增长率分别映射到散点图,通过 np.ployfit 拟合其关系并绘制拟合曲线,同时绘制 y = x 曲线进行对比。
plt.rcParams['figure.figsize'] = (10, 6)
x = changed['Pupulation Changed/%']
y = changed['White Changed/%']
# 绘制各州人口及白人增长数据
plt.scatter(x, y,
marker='o',s=120,
label='Changed of States of American',
edgecolors='tab:red',facecolor='white') # 散点图标记的轮廓及填充颜色
plt.xlabel('Pupulation Changed /%')
plt.ylabel('White Race Changed /%')
# 拟合增长率曲线,对散点进行拟合,返回元组(k,b)
f_1 = np.polyfit(x, y,deg=1)
# 绘制拟合的增长曲线
plt.plot(x,np.polyval(f_1, x),
lw=2,color='tab:orange',label='Increase Ratio of White Race')
# 绘制平衡增长曲线 y=x
plt.plot(np.linspace(0,150,20),
np.linspace(0,150,20),
color='tab:blue',
label='Increase Ratio of Balance',ls='--',lw=3)
#前面的label没有反应,只有plt.legend()才会真正标记上去
plt.legend()
#plt.text是给点加标注,给异常点加标注是哪个州
plt.text(25,75,'District of Columbia',fontsize=20,color='tab:red',ha='center',va='bottom')
plt.text(155,120,'Nevada',fontsize=20,color='tab:red',ha='center',va='bottom')
plt.title('Population & White Race Changed of States of American')
依旧看图给结论:种族增长率与人口增长率的线性关系如何,与y=x相比如何,异常点的情况如何
所有种族
用上面白色人种的方法处理全部种族,用一个for循环处理所有种族
data = df.loc[(df['Year'] == 1990) | (df['Year'] == 2019)]
# 计算美国各州人口增长率
changed = data.pivot_table(index='State', columns='Year', values='Population',aggfunc='sum')
changed['Pupulation Changed /%'] = 100 * \
(changed[2019]-changed[1990])/changed[1990]
race_columns = ['Pupulation Changed /%']
for race in ['American Indian or Alaska Native', 'Asian or Pacific Islander', 'Black or African American', 'White']:
# 计算美国各种族人口增长率
race_change = data.loc[data['Race'] == race].pivot_table(
index='State', columns='Year', values='Population',aggfunc='sum')
race_change[race+' Changed /%'] = 100 * \
(race_change[2019]-race_change[1990])/race_change[1990]
# 将人口增长率与各族人口增长率数据合并
changed = pd.concat([changed, race_change], axis=1)
race_columns.append(race+' Changed /%')
# 挑选主要字段
changed = changed[race_columns]
# 展示前5行数据
changed.head()
从图表可以看出:
每个种族的增长率变化情况,与总人口的增长率相比如何
种族增长率中最高的是哪个种族,最低的是哪个种族
异常点情况
人口结构
各年龄组构成的人口结构
将平均年龄字段按照 20,40,70 三个节点进行切分,获得 青年、壮年、中年、老年 4 个年龄分组段,聚合各分组段人数后用漏斗图可视化 1990 年的人口结构。
下图是1990年人口结构漏洞图
!pip install pyecharts==1.7.1
from pyecharts import options as opts
from pyecharts.charts import Funnel
data = df.loc[df['Year'] == 1990]
# 将平均年龄进行数据切分,生成新的组
#pd.cut用于将数据值按照值本身进行分段并排序到 bins 中
data['Age Group3'] = pd.cut(
data['Mean Age'],
bins=[0, 20, 40, 70, 100],
labels=['Youth(<20)', 'Prime(20-40)', 'Middle(40-70)', 'Old(>70)'])
data = data.groupby(['Age Group3'], as_index=False)['Population'].sum()
data['Population'] = data['Population']/np.sum(data['Population'])*100
funel = Funnel()
funel.add(
" ",
[list(z) for z in zip(data['Age Group3'], data['Population'])],
sort_='none',
label_opts=opts.LabelOpts(position="inside"),
)
funel.set_global_opts(
title_opts=opts.TitleOpts(
title="Population Struction of American Year 1990",),
legend_opts=opts.LegendOpts(
pos_top='5%', textstyle_opts=opts.TextStyleOpts(font_size=15)),
)
funel.render_notebook()
同样的,做2019年的人口结构漏斗图
data = df.loc[df['Year'] == 2019]
data['Age Group3'] = pd.cut(
data['Mean Age'],
bins=[0, 20, 40, 70, 100],
labels=['Youth(<20)', 'Prime(20-40)', 'Middle(40-70)', 'Old(>70)'])
data = data.groupby(['Age Group3'], as_index=False)['Population'].sum()
data['Population'] = data['Population']/np.sum(data['Population'])*100
funel = Funnel()
funel.add(
" ",
[list(z) for z in zip(data['Age Group3'], data['Population'])],
sort_='none',
label_opts=opts.LabelOpts(position="inside"),
)
funel.set_global_opts(
title_opts=opts.TitleOpts(
title="Population Struction of American Year 2019",),
legend_opts=opts.LegendOpts(
pos_top='5%', textstyle_opts=opts.TextStyleOpts(font_size=15)),
)
funel.render_notebook()
性别分布
fig, axs = plt.subplots(1, 3, figsize=(15, 6), sharey=True, sharex=True)
for i, year in enumerate([1990, 2010, 2019]):
ax = axs[i]
data = df.loc[df['Year'] == year].groupby(
['Gender', 'Race'], as_index=False)['Population'].sum().sort_values('Population')
data
ax.scatter(
x=data['Gender'],
y=data['Race'],
c=data['Gender'].apply(lambda x: 'tab:red' if x ==
'Female' else 'tab:blue'),
s=data['Population']*0.00007,
ec='gray',
)
ax.set_ylim(-0.5, 4)
ax.set_xlim(-1, 1.5)
ax.set_title('Year %d' % year)
if i > 0:
ax.spines['left'].set_visible(False)
fig.suptitle('Population Distribution Varies with Gender of USA',
size=25, va='bottom')