您的位置:首页 > 其它

面对日趋严重的空气污染,究竟住在海边好还是住在内陆好?

2020-03-31 18:36 447 查看

阅读提示

空气质量(Air quality) 是依据空气中污染物浓度的高低来判断的,其好坏反映了空气污染程度。随着科技与工业水平的进步,空气质量每况日下,现在已经称为了严重的全球问题,由此诞生的PM2.5、APCE蓝等网红热词不禁引人深思,本文将通过Python数据分析手段对数据深入挖掘,分析各地空气质量

目录

  • 5、 数据分析
  • 5.2 全国城市的空气质量
  • 5.3 关于空气质量猜测的验证
  • 5.4 临海城市的空气质量是否优于内陆城市?
  • 5.5 空气质量主要受到哪些因素的影响?
  • 5.6 对空气质量指数进行预测
  • 6、总结

  • 在正文开始前,想和大家分享一个视频,他是TED演讲中的一个片段:

    【TED演讲】印度很多大城市的空气质量是世界上最糟糕的。我们该如何补救这一场事关公共健康的危机?




    声明:本文思路来源于某课吧公开课,针对公开课内容进行深入剖析和扩展,尽自己所学去完善本案例,希望各位读者有所收获,谢谢阅读



    1、什么是AQI

    AQI(Air Quality Index),指空气质量指数,用来衡量空气清洁和污染的程度。AQI值越小,说明空气质量越好。而近年来空气污染日益严重,AQI指数理所应当的受到了人们的重视。

    2、任务目的

    • 判断哪些城市的空气质量较好/较差(描述性统计分析)

    • 空气质量在地理位置上的分布是否有规律性?(描述性统计分析)

    • 临海城市的空气质量是否和内陆环境有区别(推断统计分析)

    • 空气质量主要受到哪些因素的影响?(相关系数分析)

    • 全国的空气质量处于哪种水平?(区间估计)

    • 怎样预测一个城市的空气质量?(统计建模)

    3、数据集描述

    来源:2015年空气质量数据集,包含了全国主要城市的相关数据和空气质量指数(点击下载)

    4、代码实现

    4.1 库的导入

    import numpy as np
    import pandas as pd
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import warnings
    import seaborn as sns
    
    sns.set(style = "darkgrid", font = "SimHei", rc = {"axes.unicode_minus" : False })
    warnings.filterwarnings("ignore")

    4.2 加载数据集

    data = pd.read_csv("data.csv")
    print(data.shape)
    data.head()
    (325, 12)
    City AQI Precipitation GDP Temperature Longitude Latitude Altitude PopulationDensity Coastal GreenCoverageRate Incineration(10,000ton)
    0 Ngawa Prefecture 23 665.1 271.13 8.200000 102.224650 31.899410 2617.0 11 0 36.00 23.00
    1 Aksu City 137 80.4 610.00 12.276712 80.263380 41.167540 1108.0 6547 0 33.94 23.00
    2 Alxa League 85 150.0 322.58 24.200000 105.728950 38.851920 1673.0 1 0 36.00 23.00
    3 Ngari 28 74.2 37.40 1.000000 80.105800 32.501110 4280.0 1 0 36.00 23.00
    4 Anqin City 79 2127.8 1613.20 17.291781 117.034431 30.512646 13.0 2271 0 45.80 27.48

    4.3 数据清洗

    4.3.1 缺失值处理

    data.info()
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 325 entries, 0 to 324
    Data columns (total 12 columns):
    #   Column                   Non-Null Count  Dtype
    ---  ------                   --------------  -----
    0   City                     325 non-null    object
    1   AQI                      325 non-null    int64
    2   Precipitation            321 non-null    float64
    3   GDP                      325 non-null    float64
    4   Temperature              325 non-null    float64
    5   Longitude                325 non-null    float64
    6   Latitude                 325 non-null    float64
    7   Altitude                 325 non-null    float64
    8   PopulationDensity        325 non-null    int64
    9   Coastal                  325 non-null    int64
    10  GreenCoverageRate        325 non-null    float64
    11  Incineration(10,000ton)  325 non-null    float64
    dtypes: float64(8), int64(3), object(1)
    memory usage: 30.6+ KB

    在这里可以看到 Precipitation 降雨量有4个缺失值

    print(data["Precipitation"].skew())
    sns.distplot(data["Precipitation"].dropna())
    0.27360760671177387
    
    <matplotlib.axes._subplots.AxesSubplot at 0x139f3968e10>

    skew的定义

    偏度(skewness),是统计数据分布偏斜方向和程度的度量,是统计数据分布非对称程度的数字特征。偏度(Skewness)亦称偏态、偏态系数。

    表征概率分布密度曲线相对于平均值不对称程度的特征数。直观看来就是密度函数曲线尾部的相对长度。
    p=11+ez p = \frac{1}{1+e^{z}} p=1+ez1​

    data.fillna({"Precipitation" : data["Precipitation"].median()}, inplace=True)

    4.3.2 异常值的处理

    • 通过describe查看数值信息
    • 可以使用箱线图观察数据分布
    #data.describe()

    通过箱线图的呈现可以很容易的观测到离群值

    plt.figure(figsize=(15, 10))
    plt.xticks(rotation=45, fontsize=15)
    sns.boxplot(data=data)
    <matplotlib.axes._subplots.AxesSubplot at 0x139f39a3c88>

    # 当数据比较大的时候,可以使用boxenplot(信值图)
    plt.figure(figsize=(15, 10))
    plt.xticks(rotation=45, fontsize=15)
    sns.boxenplot(data=data)
    <matplotlib.axes._subplots.AxesSubplot at 0x139f3bbc3c8>

    boxplot和boxenplot的区别

    首先是

    boxplot()

    seaborn.boxplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None,
    orient=None, color=None, palette=None, saturation=0.75, width=0.8, dodge=True, fliersize=5,
    linewidth=None, whis=1.5, notch=False, ax=None, **kwargs)

    参数详解:

    • x, y, hue:数据或向量数据中的变量名称,用于绘制长格式数据的输入。

    • data:DataFrame,数组,数组列表,用于绘图的数据集。如果x和y都缺失,那么数据将被视为宽格式。否则数据被视为长格式。

    • order, hue_order:字符串列表,控制分类变量(对应的条形图)的绘制顺序,若缺失则从数据中推断分类变量的顺序。

    • orient:“v”或“h”,控制绘图的方向(垂直或水平)。这通常是从输入变量的 dtype 推断出来的,但是当“分类”变量为数值型或绘制宽格式数据时可用于指定绘图的方向。

    • color:matplotlib颜色,所有元素的颜色,或渐变调色板的种子颜色。

    • palette:调色板名称,列表或字典,用于hue变量的不同级别的颜色。可以从color_palette()得到一些解释,或者将色调级别映射到matplotlib颜色的字典。

    • saturation:float,控制用于绘制颜色的原始饱和度的比例。通常大幅填充在轻微不饱和的颜色下看起来更好,如果您希望绘图颜色与输入颜色规格完美匹配可将其设置为1。

    • width:float,不使用色调嵌套时完整元素的宽度,或主要分组变量一个级别的所有元素的宽度。

    • dodge:bool,使用色调嵌套时,元素是否应沿分类轴移动。

    • fliersize:float,用于表示异常值观察的标记的大小。

    • linewidth:float,构图元素的灰线宽度。

    • whis:float,控制在超过高低四分位数时 IQR (四分位间距)的比例,因此需要延长绘制的触须线段。超出此范围的点将被识别为异常值。

    • notch:boolean,是否使矩形框“凹陷”以指示中位数的置信区间。还可以通过plt.boxplot的一些参数来控制

    • ax:matplotlib轴,绘图时使用的 Axes 轴对象,否则使用当前 Axes 轴对象

    • kwargs:键值映射,其他在绘图时传给plt.boxplot的参数

    boxenplit()

    seaborn.boxenplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None, orient=None,
    color=None, palette=None, saturation=0.75, width=0.8, dodge=True,
    k_depth='proportion',linewidth=None, scale='exponential', outlier_prop=None,
    ax=None, **kwargs)

    boxenplot()
    的参数大体上与
    boxplot()
    差不多,但是多了三个不同的参数

    • k_depth:“proportion” 或 “tukey” 或 “trustworthy”,通过增大百分比的粒度控制绘制的盒形图数目。每个参数代表利用不同的统计特性对异常值的数量做出不同的假设。

    • scale:“linear” 或 “exponential” 或 “area”,用于控制增强箱型图宽度的方法。所有参数都会给显示效果造成影响。 “linear” 通过恒定的线性因子减小宽度,“exponential” 使用未覆盖的数据的比例调整宽度, “area” 与所覆盖的数据的百分比成比例。

    • outlier_prop:float,被认为是异常值的数据比例。与 k_depth 结合使用以确定要绘制的百分位数。默认值为 0.007 作为异常值的比例。该参数取值应在[0,1]范围内。

    t = data.copy()
    for k in t:
    if pd.api.types.is_numeric_dtype(t[k]):
    o = t[k].describe()
    IQR = o["75%"] - o["25%"]
    lower = o["25%"] - 1.5 * IQR
    upper = o["75%"] + 1.5 * IQR
    t[k][t[k] < lower] = lower
    t[k][t[k] > upper] = upper
    plt.figure(figsize=(15, 4))
    plt.xticks(rotation=45, fontsize=15)
    sns.boxplot(data=t)
    <matplotlib.axes._subplots.AxesSubplot at 0x139f5bd1978>

    现在我们已经得到了剔除离群值之后的图像了

    4.3.3 重复值处理

    • 可以使用
      duplicated()
      来检查重复,并通过keep参数进行调整
    • 找到重复值后再用
      drop_duplicate()
      进行重复值剔除
    data.duplicated().sum()
    2
    data[data.duplicated()] # 查看重复值
    City AQI Precipitation GDP Temperature Longitude Latitude Altitude PopulationDensity Coastal GreenCoverageRate Incineration(10,000ton)
    109 Baoding City 220 566.9 2757.80 13.258904 115.500183 38.857071 17.2 4565 0 30.96 49.27
    218 Luohe City 85 831.0 992.85 15.704110 114.041092 33.572510 62.0 5283 0 34.39 22.00
    data.drop_duplicates(inplace=True)

    5、 数据分析

    数据分析是呈现数据样本、提供分析结果最为根本,也是最为关键的一步,这里我们将通过柱状图观测空气质量的好坏程度。

    5.1 分析空气质量最好/最差的五个城市

    分析的结果可用来对选择旅游地点做参考

    5.1.1 空气质量最好的5个城市

    t = data[["City", "AQI"]].sort_values("AQI")
    display(t.iloc[:5])
    plt.xticks(rotation=40,fontsize=15)
    sns.barplot(x="City", y="AQI", data=t.iloc[:5])
    City AQI
    204 Shaoguan City 12
    163 Nanping City 12
    154 Meizhou City 12
    91 Keelung City 13
    195 Sanming City 13
    <matplotlib.axes._subplots.AxesSubplot at 0x139f839e6d8>

    观察图像可得出,空气质量最好的五个城市为:
    韶关市、南平市、梅州市、基隆市、三明市

    5.1.2 空气质量最差的5个城市

    display(t.iloc[-5:])
    City AQI
    105 Jiaozuo City 199
    112 Jinzhou City 202
    13 Baoding City 220
    26 Chaoyang City 224
    16 Beijing City 296
    plt.xticks(rotation=40, fontsize=15)
    sns.barplot(x="City", y="AQI", data=t.iloc[-5:])
    <matplotlib.axes._subplots.AxesSubplot at 0x139f8df00b8>

    观察图像可得出,空气质量最差的五个城市为:
    北京市、朝阳市、保定市、锦州市、焦作市

    5.2 全国城市的空气质量

    5.2.1 城市空气质量等级统计

    这里给出我国对空气质量等级的划分情况:

    根据国家给定的标准,我们对空气质量做一个范围上的规约:

    # 将AQI值转换为等级
    def value_to_level(AQI):
    if AQI >= 0 and AQI <= 50:
    return '一级'
    elif AQI >= 51 and AQI <= 100:
    return '二级'
    elif AQI >= 101 and AQI <= 150:
    return '三级'
    elif AQI >= 151 and AQI <= 200:
    return '四级'
    elif AQI >= 201 and AQI <= 300:
    return '五级'
    else:
    return '六级'

    这里,我们调用写好的函数来展示一下全国所有城市的AQI大致占比情况,并将它们可视化

    level = data['AQI'].apply(value_to_level)
    display(level.value_counts())
    sns.countplot(x=level, order=['一级','二级','三级','四级','五级','六级'])
    二级    136
    一级    103
    三级     66
    四级     14
    五级      4
    Name: AQI, dtype: int64
    
    <matplotlib.axes._subplots.AxesSubplot at 0x25c9df908c8>

    值得欣慰的是,我们国家整体城市的空气质量虽然不算太好,但也没有差到极点,至少没有出现AQI大于300的情况,观察得出主要AQI值集中在一级到二级之间,属于可以正常活动的范围,说明我国近期的环境治理方向还是比较不错的,取得了较好的效果!

    AQI数值 AQI级别 AQI类别及表示颜色 对健康影响情况 建议采取的措施
    0~50 一级 绿色 空气质量令人满意,基本无空气污染。
    51~100 二级 黄色 空气质量可接受,但某些污染物可能对极少数异常敏感人群健康有较弱影响。
    101~150 三级 轻度污染 橙色 易感人群症状有轻度加剧,健康人群出现刺激症状。
    151~200 四级 中度污染 红色 进一步加剧易感人群症状,可能对健康人群心脏、呼吸系统有影响。
    201~300 五级 重度污染 紫色 心脏病和肺病患者症状显著加剧,运动耐受力降低,健康人群普遍出现症状。
    >300 六级 严重 褐红色 健康人运动耐受力降低,有明显强烈症状,提前出现某些疾病。

    5.2.2 空气质量指数分布

    根据数据绘制全国各城市所对应的空气质量指数分部

    sns.scatterplot(x='Longitude', y='Latitude', hue='AQI', palette=plt.cm.RdYlGn_r, data=data)
    <matplotlib.axes._subplots.AxesSubplot at 0x25c9e2d4f48>

    根据经纬度分布大致来说,西部的城市要优于东部城市,南部城市要好于北部城市,而这个原因可能是西部地广人稀,污染源少且多为山脉、高原等地区而东部多为沿海且经济发达、人口密集城市,尾气、工厂等多方面因素导致了东部空气质量略差于西部。对于南北方来说,北方属于工业集中区,工厂废气排放量比较大并且气候干燥,植被覆盖率低,一到春天那就是漫天的沙尘;反观南部地区,气候湿润多雨季,植被充足,这也从一定程度上导致了南方的整体AQI要优于北方地区

    5.3 关于空气质量猜测的验证

    有这样一个有趣的说法:“全国所有的城市空气质量指数均值,大约是72”,那么这个数据究竟靠不靠谱呢?

    data['AQI'].mean()
    75.3343653250774

    我们得到了AQI的平均值为;75.3,那么问题来了:

    由于我们计算的值大于了江湖传闻中的 72,因此我们可以认为江湖传闻是胡说八道,不能相信,这个说法你认为正确吗?

    答案是显而易见的,这个说法当然是错误的。

    首先,我们要搞清楚,所谓的江湖传言“全国所有的城市空气质量指数均值,大约是72”指的是全国所有城市的平均空气质量,而我们得到的数据集只是一部分城市的空气质量,因此统计出来的数值也并不能代替整个国家所有城市的均值。

    如果真的就死磕这个江湖传言,必须要弄清楚它到底是真是假,最可靠并且最有效的方法就是:“把全国所有城市的空气指数都测定一遍,然后集中起来算平均值”。如果你满腔热血的去做这件事了,那就太傻了!这是一项非常繁重并且不现实的任务,费时又费力。

    那么除了这个方案,我们还有什么其他的办法吗?
    不知道你有没有听过一个词:“抽样调查”,我们可以对全国城市进行抽样,通过抽出的样本均值来估算总体均值

    5.3.1 中心极限定理

    如果样本总体均值为μ、方差为σ2\sigma^2σ2,进行随机抽样,样本量为n,当n逐渐增大的时候,样本的均值将会逐渐趋近于服从正态分布:Xˉ\bar{X}Xˉ~N(μ,σ2/n)N(μ,\sigma^2/n)N(μ,σ2/n)。

    根据中心极限定理我们可以得到如下结论:

    • 1.进行多次的抽样,则每次抽样会得到一个平均值,这些均值均匀的分布在总体均值附近,呈现正态分布。

    • 2.当总体样本量n足够大的时候,样本会服从正态分布。

      样本均值构成的正态分布,其均值等于总体均值μ。
    • 样本均值构成的正态分布,其标准差等于总体标准差σn\frac{\sigma}{\sqrt n}n​σ​

    说明:样本均值分布的标准差,我们称其为标准误差,简称为标准误

    # 定义总体数据
    all_ = np.random.normal(loc=30, scale=80, size=10000)
    # 创建均值数组
    mean_arr = np.zeros(1000)
    for i in range(len(mean_arr)):
    mean_arr[i] = np.random.choice(all_, size=64, replace=False).mean()
    
    print("样本均值为:{}".format(mean_arr.mean()))
    print("样本标准差为:{}".format(mean_arr.std()))
    print("偏度为:{}".format(pd.Series(mean_arr).skew()))
    sns.distplot(mean_arr)
    样本均值为:30.256196415031596
    样本标准差为:9.977226305425178
    偏度为:-0.014328566359583452
    <matplotlib.axes._subplots.AxesSubplot at 0x25c9e371788>
    

    是一个非常漂亮的正态分布曲线!

    5.3.2 置信区间

    根据正态分布的特性,对数据进行概率上的统计:

    • 以均值为中心,在一倍的标准差内,包含了大约68%的样本数据
    • 以均值为中心,在二倍的标准差内,包含了大约95%的样本数据
    • 以均值为中心,在三倍的标准差内,包含了大约99.7的样本数据
    # 定义标准差
    scale = 50
    # 定义数据
    x = np.random.normal(0, scale, size=100000)
    # 定义标准差的倍数,1到3倍
    for times in range(1, 4):
    y = x[(x >= -times * scale) & (x <= times * scale)]
    print(f"{times}倍标准差:")
    print(f"{len(y) * 100 / len(x)}%")
    1倍标准差:
    68.084%
    2倍标准差:
    95.298%
    3倍标准差:
    99.711%

    根据中心极限定理:如果多次抽样,则样本的均值构成正态分布。如果我们对总体进行一次抽样,则本次抽样的样本有95%的概率会落在二倍的标准差内,而落在区间外的概率为5%。 根据小概率事件的定义(很小的概率在一次抽样基本不会出现),如果抽样的个体均值落在了二倍标准差外的区间,我们就可以认为本次抽样的总体均值不是我们所期望的均值

    通常以二倍标准差作为判定依据,以均值为中心,正负二倍的标准差构成的区间称为置信区间,二倍标准差的区间包含了95%的数据,因此我们可以称此时的置信度为95%。换言之,我们有把握认为总体均值有百分之95%的概率会落在置信区间内。

    5.3.3 t检验

    假设检验的目的是通过收集到的数据来验证某个假设是否成立。

    我们会建立两个完全对立的假设条件,分别为原假设H0H_0H0​和备择假设H1H_1H1​,然后根据样本信息进行具体的分析和判断,计算得出P值(概率)。

    假设检验基于小概率反证法,即我们认为小概率事件在一次试验中是不会发生的如果小概率事件发生,则我们就拒绝原假设,而接受备择假设否则,我们就没
    有充分的理由推翻原假设.此时,我们选择去接受原假设

    t检验的定义: t检验,就是假设检验的一种,可以用来检验一次抽样中样本均值与总体均值的比较(二者差异是否显著)

    t=x‾−μ0Sx‾=x‾−μ0S/nt = \frac{\overline{x}-μ_0}{S_{\overline{x}}}=\frac{\overline{x}-μ_0}{S/\sqrt n}t=Sx​x−μ0​​=S/n​x−μ0​​

    x‾\overline{x}x为一次抽样中,所有个体的均值。

    μ0μ_0μ0​为待检验的均值。

    Sx‾S_{\overline{x}}Sx​为样本均值的标准差(标准误差)。

    S为一次抽样中,个体的标准差。

    n为样本容量。

    而ttt统计量服从ttt分布,当自由度(样本量-1)逐渐增大的时候,t分布近似于正态分布

    # 不同自由度的t分布与标准正态分布
    import numpy as np
    from scipy.stats import norm
    from scipy.stats import t
    import matplotlib.pyplot as plt
    
    x = np.linspace( -3, 3, 100)
    plt.plot(x, t.pdf(x,1), label='df=1')
    plt.plot(x, t.pdf(x,2), label='df=20')
    plt.plot(x, t.pdf(x,100), label = 'df=100')
    plt.plot( x[::5], norm.pdf(x[::5]),'kx', label='正态分布')
    plt.title('不同自由度下的t分布与标准正态分布')
    plt.legend()
    plt.show()

    from scipy import stats
    
    r = stats.ttest_1samp(data['AQI'], 72)
    print('t值为:{}'.format(r.statistic))
    print('p值为:{}'.format(r.pvalue))
    t值为:1.393763441074581
    p值为:0.16435019471704654

    此时的PPP值大于0.05,因此在显著性水平为0.05的检验下,我们无法拒绝原假设,因此我们要接受原假设。同样的,现在可以对全国城市的平均空气质量指数置信区间进行计算。

    n = len(data)
    df = n - 1
    left = stats.t.ppf(0.025, df=df)
    right = stats.t.ppf(0.975, df=df)
    print(left, right)
    mean= data['AQI'].mean()
    std = data['AQI'].std()
    mean + left + (std / np.sqrt(n)), mean + right * (std / np.sqrt(n))
    -1.9673585853224684 1.967358585322468
    
    (75.75935340835935, 80.0409690826239)

    现在我们得到了置信区间
    大致在75.7~80.0之间,置信度为95%

    5.3.4 破案!

    现在我们可以对江湖传言进行分析了,我们有95%的把握认为全国平均API指数落在75.7~80之间,因此我们可以拒绝接受江湖传言所认为的72的平均值

    5.4 临海城市的空气质量是否优于内陆城市?

    首先先统计临海与内陆城市的数目

    display(data['Coastal'].value_counts())
    sns.countplot(x='Coastal', data=data)
    0    243
    1     80
    Name: Coastal, dtype: int64
    
    <matplotlib.axes._subplots.AxesSubplot at 0x25c9e8083c8>

    接下来我们通过

    seaborn
    下的
    catplot()
    函数绘制散点图来观察沿海与内陆城市的AQI分布

    sns.catplot(x='Coastal', y='AQI', data=data)
    <seaborn.axisgrid.FacetGrid at 0x25ca0497688>

    由于样本数量的不同,我们也不能很确定的判断到底沿海AQI更低还是内陆AQI更低

    5.4.1 柱状图

    这里我们选择分组计算空气质量的均值

    display(data.groupby('Coastal')['AQI'].mean())
    sns.barplot(x='Coastal', y='AQI', data=data)
    Coastal
    0    79.045267
    1    64.062500
    Name: AQI, dtype: float64
    
    <matplotlib.axes._subplots.AxesSubplot at 0x25ca1589848>

    其中每个柱条的黑色的线条为误差线

    误差线源于统计学,表示数据误差(或不确定性)范围,以更准确的方式呈现数据。误差线可以用标准差(standard deviation,SD)、标准误(standard error,SE)和置信区间表示,使用时可选用任意一种表示方法并作相应说明即可。当误差线比较“长”时,一般要么是数据离散程度大,要么是数据样本少。

    柱状图中我们也仅仅只能看到沿海城市与内陆城市AQI指数的均值对比,这里我们选用箱线图来获得更多有用的信息

    5.4.2 箱线图

    sns.boxplot(x='Coastal', y='AQI', data=data)
    <matplotlib.axes._subplots.AxesSubplot at 0x25ca25ee208>

    箱线图可以很好的反映数据中的离群值

    5.4.3 小提琴图

    小提琴图 (Violin Plot) 是用来展示多组数据的分布状态以及概率密度。这种图表结合了箱形图和密度图的特征,主要用来显示数据的分布形状。跟箱形图类似,但是在密度层面展示更好。在数据量非常大不方便一个一个展示的时候小提琴图特别适用

    sns.violinplot(x='Coastal', y='AQI', data=data)
    <matplotlib.axes._subplots.AxesSubplot at 0x25ca1af6288>

    如果将散点图与小提琴放到一起呢?

    sns.violinplot(x='Coastal', y='AQI', data=data, inner=None)
    sns.swarmplot(x='Coastal', y='AQI', color='g', data=data)
    <matplotlib.axes._subplots.AxesSubplot at 0x25ca1b7ba88>

    至此,我们已经绘制了大量对我们观察数据有帮助的图形,那么从这些图形中可以获得什么信息呢?我们是否可以确定沿海城市AQI指数优于/低于内陆城市呢?

    5.4.4 t检验

    这里我们对两样本进行t检验,观察沿海与内陆城市的均值差异是否显著

    coastal = data[data['Coastal'] == 1]['AQI']
    inland = data[data['Coastal'] == 0]['AQI']
    display(coastal, inland)
    7       44
    15      23
    20     105
    37     13240      86
    ...
    304     59
    308    117
    313     45
    315     25
    317     41
    Name: AQI, Length: 80, dtype: int64
    
    0       23
    1      137
    2       85
    3       28
    4       79
    ...
    320     79
    321     86
    322    116
    323    118
    324     60
    Name: AQI, Length: 243, dtype: int64
    
    # 首先对两样本进行方差齐性检验
    stats.levene(coastal, inland)
    LeveneResult(statistic=0.08825036641952543, pvalue=0.7666054880248168)
    # 对两样本进行t检验
    stats.ttest_ind(coastal, inland, equal_var=True)
    Ttest_indResult(statistic=-2.7303827520948905, pvalue=0.006675422541012958)

    返回的第一个值为样本统计量,第二个值为p值,我们规定当p=0.006<0.05(显著性水平5%)时,我们选择拒绝原假设

    5.5 空气质量主要受到哪些因素的影响?

    这是个复杂且抽象的问题,可能是人口密度?绿化率?海拔高度?

    5.5.1 散点图矩阵

    这里我们选用

    seaborn
    自带的散点图矩阵
    sns.pairplot()
    来可视化,并通过
    hue
    来调用数据中心的
    Coastal
    属性

    # 观察地理位置 植被覆盖率 人口密度 AQI指数之间的关系
    sns.pairplot(data[['AQI', 'PopulationDensity', 'GreenCoverageRate', 'Coastal']], hue='Coastal')
    <seaborn.axisgrid.PairGrid at 0x25cab963f88>

    从图2可以清晰地看出,人口密度确实对AQI指数有一定的影响,人口约密集,出现高AQI指数的情况就越少,而图6中绿植覆盖率与AQI指数的高低好像并没有什么必然的联系

    5.5.2 相关系数

    这里我们引入一个新的概念: 相关系数,它可以用来体现两个连续变量之间的相关性,最为常用的就是皮尔逊系数。 具体的定义与公式实现请各位读者自行查阅。

    以空气质量(AQI)与降雨量(Precipitation)为例,计算二者的相关系数

    x = data['AQI']
    y = data['Precipitation']
    
    # 计算AQI与降雨量的协方差
    a = (x - x.mean()) * (y - y.mean())
    cov = np.sum(a) / (len(a) -1)
    
    # 计算AQI与降雨量的相关系数
    corr = cov / np.sqrt(x.var() * y.var())
    
    print('AQI与降雨量之间的协方差为:{}'.format(cov))
    print('AQI与降雨量之间的相关系数为:{}'.format(corr))
    AQI与降雨量之间的协方差为:-10098.209013903044
    AQI与降雨量之间的相关系数为:-0.40184407003013883

    对比各项属性之间的相关系数

    data.corr()
    AQI Precipitation GDP Temperature Longitude Latitude Altitude PopulationDensity Coastal GreenCoverageRate Incineration(10,000ton)
    AQI 1.000000 -0.401844 0.160341 -0.283956 0.093900 0.552652 -0.204753 -0.026496 -0.150656 -0.097734 0.106898
    Precipitation -0.401844 1.000000 0.176665 0.685447 0.223211 -0.656175 -0.324124 0.067047 0.259783 0.153291 0.201174
    GDP 0.160341 0.176665 1.000000 0.145780 0.173041 -0.010124 -0.208952 0.229402 0.174241 -0.039220 0.899550
    Temperature -0.283956 0.685447 0.145780 1.000000 0.141277 -0.807119 -0.459426 0.144923 0.305894 0.216575 0.173590
    Longitude 0.093900 0.223211 0.173041 0.141277 1.000000 0.173585 -0.737548 -0.121986 0.374889 0.156439 0.072068
    Latitude 0.552652 -0.656175 -0.010124 -0.807119 0.173585 1.000000 0.002571 -0.167384 -0.204199 -0.142776 -0.081412
    Altitude -0.204753 -0.324124 -0.208952 -0.459426 -0.737548 0.002571 1.000000 -0.031408 -0.271570 -0.182449 -0.122192
    PopulationDensity -0.026496 0.067047 0.229402 0.144923 -0.121986 -0.167384 -0.031408 1.000000 -0.034158 0.021197 0.283563
    Coastal -0.150656 0.259783 0.174241 0.305894 0.374889 -0.204199 -0.271570 -0.034158 1.000000 0.264419 0.158850
    GreenCoverageRate -0.097734 0.153291 -0.039220 0.216575 0.156439 -0.142776 -0.182449 0.021197 0.264419 1.000000 -0.029088
    Incineration(10,000ton) 0.106898 0.201174 0.899550 0.173590 0.072068 -0.081412 -0.122192 0.283563 0.158850 -0.029088 1.000000

    这一大堆数字脑瓜子都快看晕了吧? 做个热图看看

    5.5.3 热图

    热图可以展现数据的差异性,特别是面对庞大的数据,通过热图可视化,可以直观了解数据的分布情况或者差异情况。其次,在实际分析过程中还可以通过热图发现质量离谱的数据,协助进行质量控制。

    plt.figure(figsize=(15, 8))
    sns.heatmap(data.corr(), cmap=plt.cm.RdYlGn, annot=True, fmt='.2f')
    <matplotlib.axes._subplots.AxesSubplot at 0x25cab06e648>

    我们可以清楚地看到,影响AQI指数的主要因素是Precipitation(降雨量)和Latitude(纬度)

    那么我们可以得出结论了:

    降雨量越高,空气质量越好;维度越低,空气质量越好

    5.5.4 对热图进行更进一步的挖掘

    从图中我们还能看到其他相关度比较高的数据,比如

    • 纬度和降雨量(-0.66)
    • 纬度和温度(-0.81)
    • 降雨量和温度(0.69)

    …还有很多

    通过我们之前的分析,我们可以说沿海城市的AQI指数确实优于内陆城市,可是为什么临海(Coastal)与空气指数(AQI)之间的相关系数这么低呢?(-0.15)

    5.6 对空气质量指数进行预测

    根据我们拿到的数据,如果我们知道了降雨量,温度,经纬度、海拔高度等数据,是否可以预测它的空气质量呢?

    5.6.1 逻辑回归模型

    from sklearn.linear_model import LinearRegression
    from sklearn.model_selection import train_test_split
    
    X = data.drop(['City', 'AQI'], axis=1)
    y = data['AQI']
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)
    lr = LinearRegression()
    lr.fit(X_train, y_train)
    y_hat = lr.predict(X_test)
    print(lr.score(X_train, y_train))
    print(lr.score(X_test, y_test))
    0.4685357478390665
    0.30759980354174754
    plt.figure(figsize=(15, 8))
    plt.plot(y_test.values, '-r', label='真实值', marker='o')
    plt.plot(y_hat, '-g', label='预测值', marker='D')
    plt.legend()
    plt.title('线性回归模型预测结果', fontsize=25)
    Text(0.5, 1.0, '线性回归模型预测结果')

    其实拟合度好像不是特别好,这是因为数据在高维度的空间里,并没有呈现线性关系,从他们的相关系数中就可以看出来。

    5.6.2 随机森林

    from sklearn.ensemble import RandomForestRegressor
    
    rf = RandomForestRegressor(n_estimators=500, random_state=0)
    rf.fit(X_train, y_train)
    y_hat = rf.predict(X_test)
    print(rf.score(X_train, y_train))
    print(rf.score(X_test, y_test))
    0.9375592254941046
    0.6106531491491578
    plt.figure(figsize=(15, 8))
    plt.plot(y_test.values, '-r', label='真实值', marker='o')
    plt.plot(y_hat, '-g', label='预测值', marker='D')
    plt.legend()
    plt.title('随机森林模型预测结果', fontsize=25)
    Text(0.5, 1.0, '随机森林模型预测结果')

    6、总结

    在本文中,通过对数据的清洗、挖掘、可视化、预测四个方面实现了对全国各城市AQI指数的详细分析,可能有不足之处和错误之处,请各位读者在学习的过程中擦亮双眼,取其精华弃其糟粕。

    对数据的挖掘中我们得到了如下信息:

    • 1.空气质量总体分布上来说,南部城市优于北部城市,西部城市优于东部城市

    • 2.临海城市的空气质量整体上好于内陆城市

    • 3.是否临海,降雨量与纬度对空气质量指数的影响较大

    • 4.我国城市平均空气质量指数大致在(70.63 ~ 80 04)这个区间内,在该区间的可能性概率为95%

    空气质量不仅关乎人类生存质量,而且也深深影响着地球上其他的生物。因此我们要自觉维护环境保护义务,努力提高人类生活水平,不断改善空气质量。

    主要有以下措施:

    • 1.建立空气质量监测机制,落实国家的环境保护政策。
    • 2.加强工用能源开发,不断替代化石能源。
    • 3.发展太阳能等无污染新能源,扩展人类能源源泉。
    • 4.出台法律规定,严格限制节日爆竹燃放,减少排放有害气体。
    • 5.提供集体送暖,减少取暖成本。
    • 6.勤种树,多开河渠,减少排放污水。
    • 7.使用空气净化器防治室内空气污染。
    • 8.出行时尽量乘坐公交车、地铁,减少私家车使用;安装尾气处理器或使用燃油润滑油减少汽车尾气的排放。
    • 9.对于污染和能耗大的工厂进行改造,对废气、废水等进行无害处理,实现节能减排。

    至此,本文就要结束了,感谢各位读者的阅读,希望各位能从中学到些什么。

    • 点赞 3
    • 收藏
    • 分享
    • 文章举报
    高羊羊羊羊羊杨 发布了28 篇原创文章 · 获赞 409 · 访问量 2万+ 私信 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: