114 11 个案例掌握 Python 数据可视化--美国气候研究

美国气候研究

自哥本哈根气候会议之后,全球日益关注气候变化和温室效应等问题,并于会后建立了全球碳交易市场,分阶段分批次减碳。本实验获取了美国 1979 - 2011 年间 NASA 等机构对美国各地日均最高气温、降雨量等数据,研究及可视化了气候相关指标的变化规律及相互关系。
输入并执行魔法命令 %matplotlib inline, 并去除图例边框。

import matplotlib.pyplot as plt
%matplotlib inline

plt.rcParams['legend.frameon'] = False

准备数据

数据集介绍:
本数据集特征包括美国 49 个州(State),各州所在的地区(Region),统计年(Year),统计月(Month),平均光照(Avg Daily Sunlight),日均最大空气温度(Avg Daily Max Air Temperature ),日均最大热指数(Avg Daily Max Heat Index ),日均降雨量(Avg Daily Precipitation ),日均地表温度(Avg Day Land Surface Temperature)。
各特征的年度区间为:


image.png

导入数据并查看前 5 行。

import pandas as pd

df = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/3023/American_environment_data.csv')

df.head()

美国全境气候差异

筛选美国各大区域的主要气候指数,通过 sns.distplot 接口绘制指数的分布图。

import seaborn as sns
import numpy as np

np.random.seed(121)

data = df.copy()

regions = [' Northeast', ' Midwest', ' West', ' South']

cols = ['Avg Daily Sunlight (kJ/m2)',
        'Avg Daily Max Air Temperature (F)',
        'Avg Day Land Surface Temperature (F)',
        'Avg Daily Max Heat Index (F)',
        'Avg Daily Precipitation (mm)']


fig, axs = plt.subplots(len(regions),
                        5,
                        #                         sharey=True,
                        figsize=(16, 5),
                        )


for i, region in enumerate(regions):
    for j, col in enumerate(cols):

        ax = axs[i, j]
        # 不显示刻度及刻度标签
        ax.set_xticks([])
        ax.set_yticks([])
        # 不显示坐标轴
        for pos in ['left', 'right', 'bottom', 'top']:
            ax.spines[pos].set_visible(False)

        color = list(np.random.random(size=(1, 3))[0])
        sns.distplot(data.loc[data['Region'] == region, col],
                     ax=ax,
                     color=color,
                     kde_kws=(dict(lw=4, color='tab:blue')),
                     )
        # 最后一行添加行标题
        if i == len(np.unique(data['Region']))-1:
            ax.set_xlabel(col.split('(')[0], fontsize=14)
        else:
            ax.set_xlabel('')
            ax.set_xticks([])
        # 第一列添加列标题
        if j == 0:
            ax.set_ylabel(region, fontsize=16)
        else:
            ax.set_ylabel('')


fig.suptitle(
    'Environment Climate Distribution of Regions of USA', va='bottom', size=20)

# 调整子图间距
plt.tight_layout()

从运行结果可知:
光照能量密度(Sunlight),美国全境各地区分布趋势大致相同,均存在较为明显的两个峰(强光照和弱光照)。这是因为非赤道国家受地球公转影响,四季光照强度会呈现出一定的周期变化规律;
从地理区位能看出,东北部光照低谷明显低于其他三个区域;
日均最高空气温度(Max Air Temperature),美国全境各地区表现出较大差异,东北部和中西部趋势大致相同,气温平缓期较长,且包含一个显著的尖峰;西部地区平缓期最长,全年最高温均相对稳定;南部分布则相对更为集中;
日均地表温度(Land Surface Temperature),与最高空气温度类似,不同之处在于其低温区分布更少;
最大热指数(Max Heat Index),西部与中西部分布较为一致,偏温和性温度,东北部热指数偏高,南部偏低;
降雨量(Precipitation),西部明显偏小,南部与东北部大致相同,中西部相对较多。

结合地理知识做一个总结:
东北部及大多数中西部地区,属于温带大陆性气候,四季分明,夏季闷热,降雨较多。
西部属于温带地中海气候,全年气候温和,并且干燥少雨,夏季气候温和,最高温度相对稳定。
南部沿海一带,终年气候温暖,夏季炎热,雨水充沛。

美国全境降雨量月度分布

按月计算美国各地区降雨量均值及标准偏差,以均值 ± 一倍标准偏差绘制各地区降雨量误差线图。

import matplotlib.colors as cs
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['axes.spines.right'] = False
plt.rcParams['axes.spines.top'] = False
plt.rcParams['figure.figsize'] = (18, 6)

months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
          'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

colors = [value for value in cs.TABLEAU_COLORS.values()]
for i, region in enumerate(np.unique(df['Region'])):
    data = df.loc[df['Region'] == region]
    mean_data = data.groupby(['Month'], as_index=False).mean()
    std_data = data.groupby(['Month'], as_index=False).std()

    plt.errorbar(x=mean_data['Month'],
                 y=mean_data['Avg Daily Precipitation (mm)'],
                 yerr=std_data['Avg Daily Precipitation (mm)'],
                 fmt='o',
                 ecolor='k',
                 markersize=20,
                 alpha=0.6,
                 label=region,
                 markerfacecolor=colors[i],
                 )
    
plt.xticks(ticks=np.arange(1, 13), labels=months)
plt.legend(ncol=4)
plt.xlabel('Month')
plt.ylabel('Avg Daily Precipitation (mm)')
plt.title('Avg Daily Precipitation Distribution by Month of Region of American')

从运行结果可知:
在大多数夏季月份,西部地区降雨量远小于其他地区;
西部地区冬季月降雨量高于夏季月;
中西部地区是较为典型的温带大陆性气候,秋冬降雨逐渐减少,春夏降雨逐渐升高;
南部地区偏向海洋性气候,全年降雨量相对平均。

美国全境气候因子变化趋势研究

需要安装joypy包。

! pip install joypy

日均最高气温变化趋势
通过 joypy 包的 joyplot 接口,可以绘制带堆积效应的直方分布曲线,将 1980 年 - 2008 年的日均最高温度按每隔 4 年的方式绘制其分布图,并标注 25%、75% 分位数。

import joypy
plt.rcParams['figure.figsize'] = (7, 8)
years = np.arange(1980, 2011, 4)

data = pd.DataFrame([])

for year in years:
    data = pd.concat([data, df.loc[df['Year'] == year]])

fig, axes = joypy.joyplot(data,
                          column=['Avg Daily Max Air Temperature (F)'],
                          xlabelsize=20,
                          colormap=plt.cm.Reds,
                          alpha=0.6,
                          ylabelsize=20,
                          by='Year')


for i, year in enumerate(years):
    ax = axes[i]

    agg_df = data.loc[data['Year'] == year,
                      'Avg Daily Max Air Temperature (F)']
    
    # 标注 25% 75% 分位数
    colors=['tab:blue','tab:green']
    for j,p_value in enumerate([25, 75]):
        ax.axvline(np.percentile(agg_df, p_value),
                   ymax=0.4, ymin=0.15, color=colors[j])

plt.xlabel('Avg Daily Max Air Temperature (F)')
plt.title('Avg Daily Max Air Temperature Distribution by Year of USA', fontsize=20)

从运行结果可知:
1980 - 2008 年区间,美国全境日均最高温度分布的低温区正逐渐升高,同时高温区正逐渐降低,分布更趋向于集中;
1980 - 2008 年区间,美国全境日均最高温度的 25% 分位数和 75% 分位数有少量偏离但并不明显。
日均降雨量变化趋势
同样的方式对降雨量数据进行处理并查看输出结果。

plt.rcParams['figure.figsize'] = (7, 8)
years = np.arange(1980, 2011, 4)

data=pd.DataFrame([])

for year in years:
    data = pd.concat([data,df.loc[df['Year'] == year]])

fig, axes = joypy.joyplot(data,
                          column=['Avg Daily Precipitation (mm)'],
                          xlabelsize=20,
                          colormap=plt.cm.Blues,
                          alpha=0.6,
                          ylabelsize=20,
                          by='Year')

for i, year in enumerate(years):
    ax = axes[i]

    agg_df = data.loc[data['Year'] == year,
                      'Avg Daily Precipitation (mm)']
    
    colors=['tab:red','tab:green']
    for j,p_value in enumerate([25, 75]):
        ax.axvline(np.percentile(agg_df, p_value),
                   ymax=0.4, ymin=0.15, color=colors[j])

plt.xlabel('Avg Daily Precipitation (mm)')
plt.title('Avg Daily Precipitation Distribution by Year of USA', fontsize=20)

加州与纽约州月度降雨量分布对比

筛选出加州和纽约州的日均降雨量数据,通过 plt.hist 接口绘制降雨量各月的分布图。

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.title_fontsize'] = fontsize
plt.rcParams['axes.spines.right'] = False
plt.rcParams['axes.spines.top'] = False
plt.rcParams['figure.figsize'] = (18, 6)


months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
          'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

fig, axs = plt.subplots(1, 2)
for i, state in enumerate(['California', 'New York']):
    data = df.loc[df['State'] == state]
    ax = axs[i]
    for j, month in enumerate(months):
        month_data = data.loc[data['Month'] ==
                              j+1, 'Avg Daily Precipitation (mm)']
        ax.hist(month_data, label=month, alpha=0.8, density=True)
        ax.legend(ncol=2)
    
    if i == 0:
        ax.set_ylabel('Density of Avg Daily Precipitation')

    ax.set_xlabel('Avg Daily Precipitation (mm)')
    ax.set_title('Avg Daily Precipitation Distribution of %s of USA' % (state))
plt.tight_layout()

从运行结果可知:
加州地区降雨量多集中在 0 - 1 mm 区间,很少出现大雨,相比而言,纽约州则显得雨量充沛,日均降雨量分布在 2 - 4 mm 区间。

加州与纽约州月度降雨量分布对比-箱线图

直方图在堆积效应下会被覆盖大多数细节,同时表达聚合、离散效应的箱线图在此类问题上或许是更好的选择。
通过 sns.boxplot 接口绘制加州和纽约州全年各月降雨量分布箱线图.

data=df
data=data.loc[(data['State']=='California') | (data['State']=='New York')]

months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
          'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

sns.boxplot(x='Month',
            y='Avg Daily Precipitation (mm)',
            hue='State',
            data=data)
plt.xticks(ticks=np.arange(0,12),labels=months)

plt.title('Avg Daily Precipitation Distribution by Month of California and New York of USA')

从箱线图上,我们可以清晰地对比每个月两个州的降雨量分布,既可以看到集中程度,例如七月的加州降雨量集中在 0.1 - 0.5 mm 的窄区间,说明此时很少会有大雨;又可以看到离散情况,例如一月的加州,箱线图箱子(box)部分分布较宽,且上方 10 mm 左右存在一个离散点,说明此时的加州可能偶尔地会出现大到暴雨。

加州与纽约州月度降雨量分布对比-摆动误差线图

视觉上更为美观且简约的是摆动的误差线图,实验 「美国全境降雨量月度分布」 将所有类别标签的 x 位置均放于同一处,导致误差线高度重合。可通过调节 x 坐标位置将需要对比的序列紧凑排布。

plt.rcParams['figure.figsize'] = (18, 6)

months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
          'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

x_offset = [-0.1, 0.1]
colors = ['tab:blue', 'tab:red']
for i, state in enumerate(['California', 'New York']):
    data = df.loc[df['State'] == state]
    mean_data = data.groupby(['Month'], as_index=False).mean()
    std_data = data.groupby(['Month'], as_index=False).std()

    plt.errorbar(x=mean_data['Month']+x_offset[i],
                 y=mean_data['Avg Daily Precipitation (mm)'],
                 yerr=std_data['Avg Daily Precipitation (mm)'],
                 fmt='o',
                 ecolor='k',
                 markersize=25,
                 label=state,
                 markerfacecolor=colors[i],
                 )
plt.xticks(ticks=np.arange(1, 13), labels=months)
plt.legend()
plt.xlabel('Month')
plt.ylabel('Avg Daily Precipitation(mm)')
plt.title('Avg Daily Precipitation Distribution by Month of California and New York')

从输出结果可以看出,加州冬季的降雨量不确定更强,每年的的十一月至次年的三月,存在降雨量大,且降雨量存在忽多忽少的现象(误差线长)。

加州与纽约州降雨量与空气温度的关系

上面的实验均在研究单变量的分布,但经常性地,我们希望知道任意两个变量的联合分布有怎样的特征。
核密度估计 , 是研究此类问题的主要方式之一,sns.kdeplot 接口通过高斯核函数计算两变量的核密度函数并以等高线的形式绘制核密度。

plt.rcParams['figure.figsize'] = (14, 8)

data = df

ax = plt.figure().add_subplot(111)

for state in ['California', 'New York']:
    sns.kdeplot(
        data=data.loc[data['State'] == state,
                      'Avg Daily Max Air Temperature (F)'], 
        data2=data.loc[data['State'] == state, 'Avg Daily Precipitation (mm)'], 
        cbar=True,
        ax=ax, label=state
    )
plt.legend()
plt.ylim(-2,8)
plt.title(
    'Precipitation & Max Air Temperature Distribution')

从运行结果可知:
加州在高温区和低降雨期存在一个较为明显的高密度分布区(高温少雨的夏季);
纽约州在高温及低温区均存在一个高密度的分布区,且在不同温区降雨量分布都较为均匀。

美国全境降雨量与空气温度的关系

将美国全境的降雨量与空气温度通过 plt.hist2d 接口可视化。

plt.rcParams['figure.figsize'] = (10, 6)

data = df
fig, (ax, cax) = plt.subplots(1, 2, gridspec_kw={'width_ratios': [0.95, 0.05]})
_, _, _, mappable=ax.hist2d(x='Avg Daily Max Air Temperature (F)',y='Avg Daily Precipitation (mm)',
           data=data,bins=40,cmap=plt.cm.RdYlGn_r)

ax.set_xlabel('Avg Daily Max Air Temperature (F)')
ax.set_ylabel('Avg Daily Precipitation (mm)')
ax.set_title('Avg Daily Max Air Temperature VS Precipitation of USA')
ax.set_ylim((0,9))
plt.colorbar(mappable=mappable, cax=cax, ax=ax)
plt.show()

从运行结果可知:
美国全境最高密度的日均高温温度区域和降雨量区间分别为,78 F (约等于 25 C)和 2.2 mm 左右,属于相对舒适的生活气候区间。
美国全境降雨量与空气温度的关系-核密度估计
在上面实验基础上,在 x, y 轴上分别通过 sns.rugplot 接口绘制核密度估计的一维分布图,可在一张绘图平面上同时获取联合分布和单变量分布的特征。

plt.rcParams['figure.figsize'] = (10, 6)

sns.kdeplot(
    data=data['Avg Daily Max Air Temperature (F)'],
    data2=data['Avg Daily Precipitation (mm)'],
    cbar=True,
    shade=True,
    cmap='Blues'
)
sns.rugplot(data['Avg Daily Max Air Temperature (F)'],
            axis='x', color='tab:red', alpha=0.2)
sns.rugplot(data['Avg Daily Precipitation (mm)'],
            axis='y', color='tab:green', alpha=0.2)

plt.title('Avg Daily Max Air Temperature VS Precipitation of USA')

美国全境降雨量与空气温度的关系-散点分布和直方分布
sns.jointplot 接口通过栅格的形式,将单变量分布用子图的形式进行分别绘制,同时通过散点图进行双变量关系的展示,也是一种较好的展现数据分布的方式。

data = df

sns.jointplot(x='Avg Daily Max Air Temperature (F)', y='Avg Daily Precipitation (mm)', kind='scatter'
              , height=7  # 散点图高度
              , alpha=0.1, ec='tab:green', ratio=6  # ratio = height /joint axes 散点图与子图高度比
              , space=0.2  # space between joint and axes 散点图与子图间距
              , data=data)

美国全境日均最高气温随年份变化趋势

上面两个实验研究了双变量分布的可视化,以下研究 3 变量聚合结果的可视化。
通过 sns.heatmap 接口可实现对透视数据的可视化,其原理是对透视结果的值赋予不同的颜色块,以可视化其值的大小,并通过颜色条工具量化其值大小。

plt.rcParams['figure.figsize'] = (12, 14)

years = np.arange(1980, 2011, 4)

data=pd.DataFrame([])

for year in years:
    data = pd.concat([data,df.loc[df['Year'] == year]])
# 热力图传入的数据格式为透视数据
data = data.pivot_table(index='State', values='Avg Daily Max Air Temperature (F)',aggfunc='median',
                        columns='Year',).sort_values(years[-1],ascending=False)
sns.heatmap(data,cmap=plt.cm.RdBu_r,linewidths=0.01)

plt.title('Avg Daily Max Air Temperature Distribution by State and Year', fontsize=20)

美国全境降雨量随年份变化趋势

plt.rcParams['figure.figsize'] = (12, 14)

years = np.arange(1980, 2011, 4)

data=pd.DataFrame([])

for year in years:
    data = pd.concat([data,df.loc[df['Year'] == year]])

data = data.pivot_table(index='State', values='Avg Daily Precipitation (mm)',aggfunc='median',
                        columns='Year',).sort_values(years[-1],ascending=False)
sns.heatmap(data,cmap=plt.cm.RdBu,linewidths=0.01,)

plt.title('Avg Daily Precipitation Distribution by State and Year', fontsize=20)

显著性检验

上面的两个实验可视化了各州随年份日均最高温度的中位数变化趋势,从图中并未看出有较为显著地变化。
以下通过 t 检验的方式查看统计量是否有显著性差异。stats.ttest_ind 接口可以输出 1980 年 与 2010 年主要气候指数的显著性检验统计量及 p 值。

from scipy import stats
data = df
cols = ['Avg Daily Sunlight (kJ/m2)',
        'Avg Daily Max Air Temperature (F)',
        'Avg Daily Precipitation (mm)']

for col in cols:
    t_test = stats.ttest_ind(data.loc[data['Year'] == 1980, col],
                             data.loc[data['Year'] == 2010, col])
    print(col, t_test)

从运行结果可以看出:
检验结果拒绝了降雨量相等的原假设,即 1980 年 与 2010 年两年间,美国降雨量是不同的,同时没有拒绝日均日照、日均最大气温两个变量相等的原假设,说明气温未发生显著性变化。

你可能感兴趣的:(114 11 个案例掌握 Python 数据可视化--美国气候研究)