目录

  • 1 项目背景与分析说明
    • 1.1 项目背景
    • 1.2 数据说明
    • 1.3 分析说明
  • 2 数据预处理
    • 2.1 导入相关库
    • 2.2 导入数据
    • 2.3 数据预处理
      • 2.3.1 缺失值
      • 2.3.2 异常值
      • 2.3.3 重复值
  • 3 数据分析
    • 3.1 临海城市的空气质量是否优于内陆城市?
    • 3.2 空气质量主要受哪些因素影响?
    • 3.3 关于空气质量的验证
    • 3.4 通过线性回归建模及优化,对空气质量进行预测
      • 3.4.1 特征选择
      • 3.4.2 异常值处理
      • 3.4.3 分箱离散化
      • 3.4.4 残差图分析
    • 3.5 模型总结
  • 4 分析总结

1 项目背景与分析说明

1.1 项目背景

AQI(Air Quality Index),指空气指数,用来衡量空气清洁或污染的程度,值越小,表示空气质量越好。由于空气污染问题,近年来空气质量越来越受人们的重视。

1.2 数据说明

本数据集总记录了全国主要地区城市共325地,使用的字段有12列包括:

· City:城市名
· AQI:空气质量指数
· Precipitation:降雨量
· GDP:城市生产总值
· Temperature:湿度
· Longitude:经度
· Latitude:纬度
· Altitude:海拔高度
· PopulationDensity:人口密度
· Coastal:是否沿海
· GreenCoverageRate:绿化覆盖率
· Incineration(10,000ton):焚烧量(10,000吨)

1.3 分析说明

本次我们期望能够运用线性回归模型算法以及相关的模型优化来对全国城市空气质量进行分析,希望能够解决一下疑问:

· 临海城市的空气质量是否有别于内陆城市?
· 空气质量主要受哪些因素影响?
· 全国城市空气质量普遍处于何种水平?
· 怎样预测一个城市的空气质量?

2 数据预处理

2.1 导入相关库

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warningssns.set(style='darkgrid')
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
warnings.filterwarnings('ignore')

2.2 导入数据

data = pd.read_csv('./data.csv')
data.head(10)

数据集展示如下:

2.3 数据预处理

2.3.1 缺失值

数据集中缺失值常见处理方式

查看数据缺失情况,发现在Precipitation列中存在少量缺失

# data.info()
data.isnull().sum(axis=0)


通过数据的偏度判断数据是否左偏或是右偏,从而判断缺失值应该用均值还是用中值填充

#数据偏度
print('Precipitation列数据偏度:',data['Precipitation'].skew())
#数据分布
sns.distplot(data['Precipitation'].dropna())

结果如下:

由结果可知数据右偏,那我们在后续的填充缺失值时选用中值填充

data.fillna({'Precipitation':data['Precipitation'].median()},inplace=True)
data.isnull().sum(axis=0)

结果如下:

2.3.2 异常值
  1. 异常值查看常见方式:
  • 通过describe()查看数据信息
  • 通过3σ原则判断
  • 使用箱线图辅助
  • 相关异常检测算法

(1)通过describe()查看数据信息,虽然提供的信息全面,但异常值也不够直观,仅作为概览数据的简单方式

data.describe()

结果如下

(2)通过3σ原则判断,根据正态分布的特性,我们可以将3σ之外的数据视为异常值,此处以GDP这一列为例

sns.distplot(data["GDP"])
print(data["GDP"].skew())


可见GDP此列存在严重的右偏情况,即存在很多极大的异常值

mean, std = data["GDP"].mean(), data["GDP"].std()
lower, upper = mean - 3 * std, mean + 3 * stdprint("均值:", mean)
print("标准差:", std)
print("下限:", lower)
print("上限:", upper)
data["GDP"][(data["GDP"] < lower) | (data["GDP"] > upper)]

结果如下

(3)使用箱线图辅助,由箱线图也可得到如上的结论,存在许多极大的异常值

sns.boxplot(data=data["GDP"])

  1. 异常值处理常见方式:
  • 删除异常值
  • 视为缺失值处理
  • 对数转换
  • 使用临界值填充
  • 使用分箱离散化处理

(1)对数转换
如果数据中存在较大的异常值,我们可以通过取对数来进行转化,这样可以得到一定程度的缓解

fig, ax = plt.subplots(1, 2)
fig.set_size_inches(15, 5)
sns.distplot(data["GDP"], ax=ax[0])
sns.distplot(np.log(data["GDP"]), ax=ax[1])

如图,取对数后的分布图比原分布图显得更加正态

取对数的方式比较简单,不过也存在一些局限:

  • 取对数只能针对正数操作,不过我们可以通过如下方式进行转换:
np.sign(X)*np.log(np.abs(X)+1)
#通过sign取符号,通过+1来防止X出现0的情况
  • 适用于右偏分布,不适用与左偏分布

(2)使用边界值替换
我们可以通过对异常值进行“截断”处理,即使用临界值替换异常值,例如,在3σ与箱线图中,就可以这样处理

(3)分箱离散化
有时候特征对目标存在一定影响,但是,这种影响可能未必是线性的增加,此时,我们可以通过分箱的方式,对特征进行离散化处理。

2.3.3 重复值
  1. 重复值查看
    使用duplicate检查重复值,可配合keep参数进行调整
# 发现重复值。
print(data.duplicated().sum())
# 查看哪些记录出现了重复值。
data[data.duplicated(keep=False)]

结果如下:

  1. 重复值处理
    重复值对分析通常没有作用,直接删除即可
data.drop_duplicates(inplace=True)
data.duplicated().sum()

3 数据分析

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

我们先来看一下临海与内陆城市的数量与AQI均值

display(data["Coastal"].value_counts())
display(data.groupby("Coastal")["AQI"].mean())
sns.barplot(x="Coastal", y="AQI", data=data)


进行方差齐性检验

from scipy import statscoastal = data[data["Coastal"] == "是"]["AQI"]
inland = data[data["Coastal"] == "否"]["AQI"]# 进行方差齐性检验,为后续的两样本t检验服务
stats.levene(coastal,inland)

得到的结果为:statistic=0.08825036641952543, pvalue=0.7666054880248168

进行两样本t检验。equal_var设置两个样本的方差是否是一致的,在levene中给出的P值可认为当前这两个样本的方差一致。

# 注意一点,两样本的方差相同与不相同,取得的结果是不同的。
r = stats.ttest_ind(coastal,inland,equal_var=True)
print(r)
#这边给出的判断是双边检验,而我们要的结果是 临海是否小于内陆,是单边检验
p = stats.t.sf(r.statistic,df=len(coastal)+len(inland)-2)
#单边检验和双边检验的统计量statistic是一致的,df为自由度
print(p)

得到的结果为:pvalue=0.9966622887294936
故有超过99%的概率认为临海城市的AQI低于内陆城市

3.2 空气质量主要受哪些因素影响?

通过热力图可看出各个特征之间的相关程度

plt.figure(figsize=(15, 10))
ax = sns.heatmap(data.corr(), cmap=plt.cm.YlOrRd, annot=True, fmt=".2f",alpha=0.85)
# 注意:Matplotlib 3.1.1版本的bug,heatmap的首行与末行会显示不全。
# 可手动调整y轴的范围来进行修复。(老版本的Matplotlib不需要调整y轴范围。)
# a, b = ax.get_ylim()
# ax.set_ylim(a + 0.5, b - 0.5)


从结果可知,空气质量指数主要受降雨量(-0.40)与维度(0.55)影响

  • 降雨量越多,AQI越低,空气质量越好
  • 维度越低,AQI越低,空气质量越好

3.3 关于空气质量的验证

有传言称全国所有城市的空气质量指数均值为71?

display(data["AQI"].mean())
stats.ttest_1samp(data["AQI"], 71)

结果为:pvalue=0.07095431526986647
可以看到,P值大于0.05,我们无法拒绝原假设,因此选择接受

mean = data["AQI"].mean()
std = data["AQI"].std()
stats.t.interval(0.95,df=len(data)-1,loc=mean,scale=std/np.sqrt(len(data)))

通过计算可得,全国所有城市的平均空气质量指数,95%的可能在大致区间(70.63, 80.04)中

3.4 通过线性回归建模及优化,对空气质量进行预测

对于某城市,如果我们已知降雨量,温度,经纬度等指标,通过对已知的数据建模,应用于未知的数据,进而预测结果。
(1)数据转换
对于模型来说,内部进行的都是数学上的运算。在进行建模之前,我们需要先进行数据转换,将类别变量转换为离散变量。

(2)基础模型

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_splitX = 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.3, random_state=0)lr = LinearRegression()
lr.fit(X_train, y_train)
print(lr.score(X_train, y_train))
print(lr.score(X_test, y_test))

计算得到的训练集和测试集的R2R^2R2分别为:0.4538897765064036
0.40407705623832957

y_hat = lr.predict(X_test)
plt.figure(figsize=(15,5))
plt.plot(y_test.values,"-r",label="真实值",marker="o")
plt.plot(y_hat,"-g",label="预测值",marker="D")
plt.legend(loc="upper left")
plt.title("线性回归预测结果",fontsize=20)

3.4.1 特征选择

刚才,我们使用所有可能的原始数据作为特征,建立模型,然而,特征并非越多越好,有些特征可能对模型质量并没有什么改善,我们可以进行删除,同时,也能够提高模型训练速度。

(1)RFECV
特征选择的方式有很多,这里我们选择使用RFECV方法来实现特征选择,RFECV分成两个部分,分别是:

  • RFE(recursive feature elimination):递归特征消除,用来对特征进行重要性评级。
  • CV(cross validation):交叉验证,在特征评级后,通过交叉验证,选择最佳数量的特征。

具体过程如下:
RFE阶段:
1.初始的特征集为所有可用的特征。
2.使用当前特征集进行建模,然后计算每个特征的重要性。
3.删除最不重要的一个(或多个)特征,更新特征集。
4.跳转到步骤2,直到完成所有特征的重要性评级。
CV阶段:
1.根据RFE阶段确定的特征重要性,依次选择不同数量的特征。
2.对选定的特征集进行交叉验证。
3.确定平均分最高的特征数量,完成特征选择。

from sklearn.feature_selection import RFECV# estimator: 要操作的模型
# step: 每次删除的变量数
# cv: 使用的交叉验证折数
# n_jobs: 并发的数量
# scoring: 评估的方式rfecv = RFECV(estimator=lr, step=1, cv=5, n_jobs=-1, scoring="r2")
rfecv.fit(X_train,y_train)
# 返回经过选择之后,剩余的特征数量
print(rfecv.n_features_)
# 返回经过特征选择后,使用缩减特征训练后的模型
print(rfecv.estimator_)
# 返回每个特征的等级,数值越小,特征越重要
print(rfecv.ranking_)
# 返回布尔数组,用来表示特征是否被选择
print(rfecv.support_)
# 返回对应数量特征时,模型交叉验证时的评分
print(rfecv.grid_scores_)


通过结果可知,我们成功删除了两个特征,在特征选择过程中,使用交叉验证获得的R2R^2R2值变化如下:

plt.plot(range(1, len(rfecv.grid_scores_) + 1), rfecv.grid_scores_, marker="o")
plt.xlabel("特征数量")
plt.ylabel("交叉验证$R^2$值")


我们对测试集应用这种特征选择,进行测试,获取测试结果

print("剔除的变量:", X_train.columns[~rfecv.support_])
X_train_eli = rfecv.transform(X_train)
X_test_eli = rfecv.transform(X_test)
print(rfecv.estimator_.score(X_train_eli, y_train))
print(rfecv.estimator_.score(X_test_eli, y_test))


我们发现,经过特征选择后,消除了GDP与PopulationDensity两个特征,而使用剩余8个特征训练的模型,与之前未消除特征训练的模型,无论在训练集还是测试集的表现上,都几乎相同,这就证明,我们消除的这两个特征,确实对拟合目标没有什么帮助,可以去掉。

3.4.2 异常值处理

如果数据中存在异常值,很有可能会影响模型的效果,这里我们选择使用临界值替换异常值。

# Coastal是类别变量,映射为离散变量,不会有异常值
for i in X.columns.drop("Coastal"):if pd.api.types.is_numeric_dtype(X_train[i]):quartile = np.quantile(X_train[i], [0.25, 0.75])IQR = quartile[1] - quartile[0]lower = quartile[0] - 1.5 * IQRupper = quartile[1] + 1.5 * IQRX_train[i][X_train[i] < lower] = lowerX_train[i][X_train[i] > upper] = upperX_test[i][X_test[i] < lower] = lowerX_test[i][X_test[i] > upper] = upperlr.fit(X_train,y_train)
print(lr.score(X_train,y_train))
print(lr.score(X_test,y_test))


去除异常值之后,我们使用新的训练集和测试集来评估模型的效果。
效果对比之前,有轻微改进,我们可以使用RFECV在去除异常值的数据上,再次尝试。

rfecv = RFECV(estimator=lr, step=1, cv=5, n_jobs=-1, scoring="r2")
rfecv.fit(X_train, y_train)
print(rfecv.n_features_)
print(rfecv.ranking_)
print(rfecv.support_)
print(rfecv.grid_scores_)plt.plot(range(1, len(rfecv.grid_scores_) + 1), rfecv.grid_scores_, marker="o")
plt.xlabel("特征数量")
plt.ylabel("交叉验证$R^2$值")

print("剔除的变量:", X_train.columns[~rfecv.support_])
# X_train_eli = rfecv.transform(X_train)
# X_test_eli = rfecv.transform(X_test)
# 为了方便后面列的筛选操作,这里我们换一种方式转换。
X_train_eli = X_train[X_train.columns[rfecv.support_]]
X_test_eli = X_test[X_test.columns[rfecv.support_]]
print(rfecv.estimator_.score(X_train_eli, y_train))
print(rfecv.estimator_.score(X_test_eli, y_test))

3.4.3 分箱离散化

注意:分箱后,我们不能将每个区间映射为离散数值,而是应当使用One-Hot编码

from sklearn.preprocessing import KBinsDiscretizer
# KBinsDiscretizer K个分箱的离散器。用于将数值(通常是连续变量)变量进行区间离散化操作
# n_bins:分箱(区间)的个数
# encode:离散化编码方式。分为:onehot,onehot-dense与ordinal
#     onehot:使用独热编码,返回稀疏矩阵
#     onehot-dense:使用独热编码,返回稠密矩阵
#     ordinal:使用序数编码(0,1,2……)
# strategy:分箱的方式。分为:uniform,quantile,kmeans
#     uniform:每个区间的长度范围大致相同
#     quantile:每个区间包含的元素个数大致相同
#     kmeans:使用一维kmeans方式进行分箱k = KBinsDiscretizer(n_bins=[4,5,15,6], encode="onehot-dense", strategy="uniform")
# 定义离散化的特征
discretize = ["Longitude", "Temperature", "Precipitation", "Latitude"]r = k.fit_transform(X_train_eli[discretize])
r = pd.DataFrame(r,index=X_train_eli.index)# 将离散化的特征重新组合回原特征组
X_train_dis = X_train_eli.drop(discretize,axis=1)
X_train_dis = pd.concat([X_train_dis,r],axis=1)# 对测试集进行相同操作
r = pd.DataFrame(k.transform(X_test_eli[discretize]),index=X_test_eli.index)
X_test_dis = X_test_eli.drop(discretize,axis=1)
X_test_dis = pd.concat([X_test_dis,r],axis=1)lr.fit(X_train_dis,y_train)
print(lr.score(X_train_dis,y_train))
print(lr.score(X_test_dis,y_test))

由此得到的数据进行训练后的结果如下

可见,离散化操作后,模型效果有了进一步提升。

此外,在分箱离散化的过程中,选择特征数量不同以及分箱数量不同都会产生不同的结果,应该多多尝试不同的组合。

3.4.4 残差图分析

残差,就是模型预测值与真实值之间的差异,我们可以绘制残差图,来对回归模型进行评估。残差图的横坐标为预测值,纵坐标为残差值。

对于一个好的回归模型,误差应该随机分布的。因此,残差也应随机分布与中心线附近,如果我们从残差图中找出变化规律,这就意味着模型遗漏了某些能够影响残差的解释信息。

  • 异方差性
    是指残差具有明显的方差不一致性,这里我们异常值处理前后的两组数据,分别训练模型,然后观察残差的效果
fig, ax = plt.subplots(1, 2)
fig.set_size_inches(15, 5)
data = [X_train, X_train_dis]
title = ["原始数据", "处理后数据"]
for d, a, t in zip(data, ax, title):model = LinearRegression()model.fit(d, y_train)y_hat_train = model.predict(d)residual = y_hat_train - y_train.valuesa.set_xlabel("预测值")a.set_ylabel(" 残差")a.axhline(y=0, color="red")a.set_title(t)sns.scatterplot(x=y_hat_train, y=residual, ax=a)


在左图中,我们发现,随着预测值的增大,模型的误差也在增大,对于这种情况,我们可以对目标y值取对数的方式处理。

y_train_log = np.log(y_train)
y_test_log = np.log(y_test)
lr.fit(X_train, y_train_log)y_hat_train = lr.predict(X_train)
residual = y_hat_train - y_train_log.values
plt.xlabel("预测值")
plt.ylabel(" 残差")
plt.axhline(y=0, color="red")
sns.scatterplot(x=y_hat_train, y=residual)


此时,异方差性得到解决,同时模型的效果也可以得到一定的提升。

  • 离群点
    如果是简单线性回归,我们可以通过绘制回归线轻松看出是否存在一些离群点。然而对多远线性回归,其回归线已经拓展成超平面,无法通过可视化来观察。

然而还是可以通过绘制残差图,通过预测值与实际值之间的关系,来检测离群点

model = LinearRegression()
model.fit(X_train_dis, y_train)
y_hat_train = model.predict(X_train_dis)
residual = y_hat_train - y_train.valuesr = (residual - residual.mean()) / residual.std()plt.xlabel("预测值")
plt.ylabel(" 残差")
plt.axhline(y=0, color="red")
sns.scatterplot(x=y_hat_train[np.abs(r) <= 2], y=residual[np.abs(r) <= 2], color="b", label="正常值")
sns.scatterplot(x=y_hat_train[np.abs(r) > 2], y=residual[np.abs(r) > 2], color="orange", label="异常值")


使用剔除离群点后的数据进行训练后

X_train_dis_filter = X_train_dis[np.abs(r) <= 2]
y_train_filter = y_train[np.abs(r) <= 2]
lr.fit(X_train_dis_filter, y_train_filter)
print(lr.score(X_train_dis_filter, y_train_filter))
print(lr.score(X_test_dis, y_test))


由此可见,模型效果又进一步提升了。

3.5 模型总结

本文线性回归模型的优化方向为:

  • 特征选择 – 通过RFECV的方式进行特征筛选
  • 使用临界值处理异常值
  • 分箱离散化
  • 残差分析 – 离群点剔除

4 分析总结

1.临海城市的空气质量整体好于内陆城市。
2.是否临海,降雨量与纬度对空气质量指数的影响较大。
3.我国城市的平均空气质量指数有95%的可信度大致在(70.63,80.04)这个区间内。
4.通过已有数据,我们可以对未知地区的空气质量指数进行预测。

通过线性回归模型及优化实现AQI分析与预测相关推荐

  1. python之AQI分析与预测

    AQI分析与预测 背景介绍 AQI,指空气质量指数,用来衡量空气清洁或污染的程度.值越小,表示空气质量越好. 分析目标 哪些城市的空气质量较好/较差? 空气质量在地理位置分布上,是否具有一定的规律性? ...

  2. 使用python及相关库实现AQI分析与预测

    使用python及相关库实现AQI分析与预测 前言 一.需求背景 二.提出问题 三.数据预览 四.数据清洗 五.数据分析 六.总结 前言 一.需求背景 AQI(Air Quality Index),即 ...

  3. 原理 + 代码 | Python 实现多元线性回归模型 (建模 + 优化,附源数据)

    前言 多元线性回归模型非常常见,是大多数人入门机器学习的第一个案例,尽管如此,里面还是有许多值得学习和注意的地方.其中多元共线性这个问题将贯穿所有的机器学习模型,所以本文会将原理知识穿插于代码段中,争 ...

  4. 分析项目-AQI分析与预测

    文章目录 一:项目背景 二:简单聊分析流程 三:买菜,数据获取 四:洗菜,数据清洗 数据预处理 数据清洗 缺失值 异常值 重复值 五:切菜,数据转换 六:炒菜,数据分析 哪些城市的空气质量较好/较差? ...

  5. 基于Python的机器学习模型对公司人员离职情况分析及预测

    一.背景 Ⅰ 数据来源 Ⅱ 数据背景 Ⅲ 分析目的 二.数据探索性分析 Ⅰ 数据类型 Ⅱ 描述性统计 Ⅲ 数据预处理 a.缺失值处理 b.异常值处理 c.重复值处理 三.数据分析 Ⅰ 可视化分析 a. ...

  6. ipat模型matlab代码,基于IPAT模型的河北省灰水足迹分析及预测

    摘要: 河北作为京津冀发展圈的重要组成部分,水质水量问题突出,因此迫切需要对其水量和水质进行研究.基于农业和工业生活两部分,选取N肥,P肥,COD为关键污染物,以水环境最大允许容量为依据,计算了河北省 ...

  7. 基于机器学习梯度下降优化算法来寻找最佳的线性回归模型

    https://www.toutiao.com/a6638782437587419652/ 幻风的AI之路 2018-12-25 18:12:27 线性回归模型 线性回归模型是一个非常简单的算法模型, ...

  8. AQI空气质量分析与预测

    AQI分析与预测 背景信息 AQI全称是Air Quality Index,指空气质量指数,用来衡量空气清洁或者污染的程度,值越小,表示空气质量越好. 本文的分析目标 一.描述性统计 哪些城市的空气质 ...

  9. 基于多元线性回归的股票分析与预测——R语言

    基于多元线性回归的股票分析与预测 一.数据来源 1.自变量 2.因变量 二.多元线性回归 1. 初步建立多元线性回归模型 (1)数据集划分 (2)建立回归模型 2. 多元线性回归模型的优化 3.模型误 ...

最新文章

  1. java动态添加view
  2. Highcharts数据表示(3)
  3. 三目运算符_C语言知识点:运算符的优先级和结合性
  4. Python练习:期末测评
  5. Eclipse如何新建TOMCAT并配置Server Locations和Publishing属性
  6. verlet-rope-latest 的扩展—— BYRope
  7. 机器学习中的数学——距离定义(二十一):JS散度(Jensen–Shannon Divergence)
  8. 网吧里电脑提示计算机内存不足,网吧电脑显示虚拟内存不足该怎么办呢
  9. 我知道的Activity
  10. 小米怎么卸载html,小米11内容中心有什么用?怎么关闭和卸载呢
  11. web前端简易网页制作
  12. Linux内核的配置和编译
  13. Java Web快速开发框架 ---- JSPX (一)
  14. Node安装及更换源
  15. 使用html2canvas 截图 出现图片空白的问题
  16. 从零开始使用AntDB
  17. 阻容感原件选择标规范
  18. ComM(通信管理)和CanNm(network)
  19. 第五章 C++与STL入门 例题
  20. 处理四种ADSL掉线的故障问题【丶Demond CSDN博客】

热门文章

  1. DevExpress控件学习总结 z
  2. HelloWord代码
  3. zabbix_get [71696]: Check access restrictions in Zabbix agent configuration
  4. Ardupilot移植经验分享(2)
  5. python 时间记录
  6. IRP(I/O Request Package)详解
  7. windows内核开发学习笔记十五:IRP结构
  8. JAVA计算机毕业设计校园订餐系统(附源码、数据库)
  9. C1认证学习十三(数据结构常识)
  10. python 导入excel 分词_如何对excel表格里的词结巴分词python