面对日趋严重的空气污染,究竟住在海边好还是住在内陆好?
阅读提示
空气质量(Air quality) 是依据空气中污染物浓度的高低来判断的,其好坏反映了空气污染程度。随着科技与工业水平的进步,空气质量每况日下,现在已经称为了严重的全球问题,由此诞生的PM2.5、APCE蓝等网红热词不禁引人深思,本文将通过Python数据分析手段对数据深入挖掘,分析各地空气质量。
目录
在正文开始前,想和大家分享一个视频,他是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=Sxx−μ0=S/nx−μ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
- 收藏
- 分享
- 文章举报
- 谷歌遭遇史上最严重高管离职潮 内斗还是厌倦?
- Logout: 究竟用GET还是POST?
- 究竟让上司做选择题还是判断题?
- java中究竟是传值还是传引用?
- Kafka无法消费!?究竟是bug的“沦陷”还是配置的“扭曲”?
- 干货(强烈推荐)面对泡沫,政府是保房价还是保汇率?(强烈推荐)
- 漫谈项目管理之:面对严重的技术问题,你应该怎么做?
- 裁员还是IT主旋律吗?IT人如何面对新劳动合同法
- 面对客户的需求变更,接受还是拒绝?
- 究竟是社会不公平,还是我们太浮躁?
- 关于某些数据究竟是删除了再添加好还是直接修改比较好
- 那些坑爹的老代码,究竟改还是不改?!
- 数据库中存储日期的字段类型究竟应该用varchar还是datetime ?
- 究竟是昨天(2.3)立春还是今天(2.4)立春?易语言告诉你真相
- 究竟需要使用检查型Exception还是非检查型Exception(RuntimeException)
- Windows内核开发中如何区分文件对象究竟是文件还是文件夹?(FILE_OBJECT包括了无数详细信息)
- 面对数字媒体是拒绝还是合作?纽约时报向Flipboard低头
- 创业者和投资人之间究竟是恋人还是敌人呢?
- 浅谈在Java语言中究竟是传值还是传引用
- SNS究竟是资本看好的下一个金矿,还是创业者一厢情愿的狂热?