Python AQI空气污染指数数据分析与机器学习

 

导入模块

import numpy as np
import pandas as pd
import datetime
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.pylab as pylab
import seaborn as sns
%matplotlib inline
# Configure visualisations
sns.set_style()

读取数据,查看数据列表

# 读取数据
data=pd.read_csv('train.csv')
# 查看数据列名称
data.columns
# 查看数据头与尾
data.head()
data.tail()
# 查看数据基本统计信息
data.describe()
# 查看数据存储类型
data.info()

由于数据也是个时间序列,所以我们可以先大致看一下AQI在不同时间尺度下的趋势。字段中date和time在一起,我们首先要把他们拆分开来看。

temp=pd.DatetimeIndex(data['datetime'])
# 增加一列数据
data['date']=temp.date
data['time']=temp.time

data.head()
data.tail()

data['month']=temp.month
data['day']=temp.day
data['hour']=temp.hour
data['week']=temp.weekofyear
data.head()

取出某一个地区的数据

data_A3=data[data['STATIONNAME'].str.contains('A3')]
data_A3.head()

首先,我们看一下2015年前8个月的变化趋势,从图上看,没有什么太多惊喜,好像是第一季度AQI值高的比较多,和我们平时的感觉是一样的,冬天污染却是要严重一下。

画时间与AQI的分布图

plt.figure(figsize=(16,8))
plt.plot(data_A3['date'],data_A3['AQI'])
plt.title('Trend of AQI')
plt.ylabel('AQI')
plt.legend(loc='best')

画每一个月份与AQI的分布图

plt.figure(figsize=(12,8))
# 画箱线图
sns.boxplot(x='month', y='AQI', data=data_A3)
plt.ylabel('AQI', fontsize=12)
plt.xlabel('month', fontsize=12)
plt.title('Median distribution by month')
plt.show()

画一个月中每一天AQI的分布图

#month
plt.figure(figsize=(12,8))
sns.pointplot(x='day', y='AQI', data=data_A3)
plt.ylabel('AQI', fontsize=12)
plt.xlabel('date of month', fontsize=12)
plt.title('By month')
plt.show()

画一年中所有周的AQI的分布图

#week
plt.figure(figsize=(12,8))
sns.pointplot(x="week", y="AQI", data=data_A3)
plt.ylabel('AQI', fontsize=12)
plt.xlabel('week of year', fontsize=12)
plt.title('By week')
plt.show()

画一天中24小时的AQI的分布图

#one day
plt.figure(figsize=(12,8))
sns.pointplot(x="hour", y="AQI", data=data_A3)
plt.ylabel('AQI', fontsize=12)
plt.xlabel('24 hours', fontsize=12)
plt.title('By hour')
plt.show()

画出一天中24小时的AQI的分布图的散点图表示

#one day---another way
plt.figure(figsize=(12,8))
sns.stripplot(x="hour", y="AQI", data=data_A3)
plt.ylabel('AQI', fontsize=12)
plt.xlabel('24 hours', fontsize=12)
plt.title('By hour')
plt.show()

从上面对AQI在时间尺度上的可视化结果,可以看出,AQI的变化趋势有时间上的周期性影响,因此,在之后的特征选择上需要考虑到时间因素。

下面,我们来分析一下AQI和6个指标的相关关系。首先我们不分地点计算相关性,然后再以A3为例进行可视化展示。

画相关矩阵图

co_data=data[['AQI','PM2.5','PM10','NO2','O3','CO','SO2']]
g=sns.PairGrid(co_data)
g.map(plt.scatter)

画相关性热力图

#相关性热度图
def plot_corr_map(df):
    corr=df.corr()
    _,ax=plt.subplots(figsize=(12,10))
    cmap=sns.diverging_palette(220,10,as_cmap=True)
    _=sns.heatmap(
        corr,
        cmap=cmap,
        square=True,
        cbar_kws={'shrink':0.9},
        ax=ax,
        annot=True,
        annot_kws={'fontsize':12})
plot_corr_map(co_data)

seaborn做出来的图还是很漂亮的,从上面的相关关系矩阵可以发现O3与AQI的相关性最低,基本没有相关性,原因估计也比较复杂,需要专业人士去解读。我按照自己的理解认为:(1)AQI计算时,O3 权重较小,NOx 权重较大,PM2.5 权重最大,O3与它们都是负相关;(2)按AQI计算规则,臭氧1小时浓度值不用于计算每天的AQI指数,仅用来反映小时健康影响程度,提示直接接触臭氧污染的人群应采取防护措施,而日均AQI指数计算采用臭氧8小时滑动平均值。

研究每一个地区的情况

#地点A3的情况
co_data_A3=data_A3[['AQI','PM2.5','PM10','NO2','O3','CO','SO2']]
g=sns.PairGrid(co_data_A3)
g.map(plt.scatter)

通过上面对数据的挖掘和理解,可以发现,时间对AQI的影响相当重要,因此,在需要把Month、Week、Day、Hour等不同的时间尺度作为特征加入到数据去训练模型;另外,O3与AQI基本不存在相关性,因此,可以把O3从数据中删除,减少对训练模型的影响。

data.head()
#remove old data features
data_new=data.drop(['datetime','O3','date','time'],axis=1)
data_new.head()
data_new.shape

查看数据空值情况,并用中位数,平均数,填充空缺值

nans=pd.isnull(data_new).sum()
nans[nans>0]

#对AQI、PM2.5、NO2、03、CO和SO2采用均值填充
data_new['AQI']=data_new['AQI'].fillna(data_new['AQI'].mean())
data_new['PM2.5']=data_new['PM2.5'].fillna(data_new['PM2.5'].mean())
data_new['NO2']=data_new['NO2'].fillna(data_new['NO2'].mean())
data_new['CO']=data_new['CO'].fillna(data_new['CO'].mean())
data_new['SO2']=data_new['SO2'].fillna(data_new['SO2'].mean())

nans=pd.isnull(data_new).sum()
nans[nans>0]

对于PM10来说,缺失值小于1/3,但也缺失较多,考虑到其随机性因素,不能用均值等方法填充,这里采用随机森林建立模型的方法。

#采用随机森林算法建立模型来填充PM10的缺失值,即利用数据表中某些没有缺失的特征属性来预测某特征属性的缺失值
def fill_missing_PM10(df):
    from sklearn.ensemble import RandomForestRegressor
    temp=df[['PM10','AQI','PM2.5','NO2','CO','SO2']]
    #分成已知该特征和未知该特征两个部分
    known=temp[temp.PM10.notnull()].as_matrix() 
    unknown=temp[temp.PM10.isnull()].as_matrix()
    #X为特征属性值
    X=known[:,1:]
    #y为结果标签值
    y=known[:,0]
    #fit to a RandomForestRegressor model
    rfr=RandomForestRegressor(n_estimators=2000,n_jobs=-1)
    rfr.fit(X,y)
    #利用得到的model进行未知特征值预测
    predicted=rfr.predict(unknown[:,1:])
    #将预测结果fill the missing values
    df.loc[df.PM10.isnull(),'PM10']=predicted
    return df,rfr
#调用函数进行PM10缺失值填充
data_new,rfr=fill_missing_PM10(data_new)

接下来使用整个表的数据,进行模型训练,

from sklearn.feature_extraction import DictVectorizer

# 我们把连续值的特征放入一个dict中
feature_con=['PM2.5','PM10','NO2','CO','SO2','month','day','week','hour']
data_feature_con=data_new[feature_con]
X_con=data_feature_con.T.to_dict().values() 

# 向量化特征
vec=DictVectorizer(sparse=False)
X_con_vec=vec.fit_transform(X_con)

data_feature_con.head()

X_con_vec

对数据进行正规化

对数型值属性做一些处理,把其值缩减至0-1之间,这样的数据放到模型里,对模型训练的收敛和模型的准确性都有好处。这里采用MinMaxScaler方法。

# normalize the con features
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1))
X_con_vec=scaler.fit_transform(X_con_vec)
X_con_vec

地区需要进行one-hot编码

对于类别特征,通过one_hot编码进行处理,采用pandas的get_dummies函数。

#one-hot encoding
dummies_cat_feature=pd.get_dummies(data_new['STATIONNAME'])
dummies_cat_feature=dummies_cat_feature.rename(columns=lambda x: "STATIONNAME_"+str(x))
dummies_cat_feature.head()
# 同样,把编码后的表放入dict中
X_cat=dummies_cat_feature.T.to_dict().values() 
X_cat
# 向量化特征
X_cat_vec=vec.fit_transform(X_cat)
X_cat_vec
X_cat_vec.shape
# combine cat & con features
X_vec=np.concatenate((X_con_vec,X_cat_vec),axis=1)
X_vec
X_vec.shape

预测值AQI处理

#对AQI向量化
Y_vec=data_new['AQI'].values.astype(float)
#对AQI最大最小化
# Y_vec=scaler.fit_transform(Y_vec)
# Y_vec=scaler.fit_transform(Y_vec)
Y_vec

拆分训练集和测试集

​
from sklearn import cross_validation
X_train,X_test,y_train,y_test=cross_validation.train_test_split(X_vec,Y_vec,test_size=0.3,random_state=0)
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)

​

评估函数

def model_evaluation(model,X_tr,y_tr,X_te,y_te):
    from sklearn import metrics
    from sklearn.cross_validation import cross_val_score
    #建立模型
    model.fit(X_tr,y_tr)
    #预测
    y_pr=model.predict(X_te)
    #打印结果
    print ("Correlation Coefficient:",np.corrcoef(y_te,y_pr))
    print ("---------------------------")
    print ("RMSE:",np.sqrt(metrics.mean_squared_error(y_te, y_pr)))
    print ("---------------------------")
    print ("Determination Coefficient(R2):train score",model.score(X_tr,y_tr),"test score",model.score(X_te,y_te))
    print ("---------------------------")
    scores=cross_val_score(model,X_tr,y_tr)
    print ("Cross-validation score:",scores.mean())
    return model,y_pr

第一种模型采用最简单的线性回归进行学习预测。

from sklearn.linear_model import LinearRegression
lr=LinearRegression()
m,y_predict_linear=model_evaluation(lr,X_train,y_train,X_test,y_test)
y_predict_linear

第二种使用单层神经网络模型

from sklearn.neural_network import MLPRegressor
mlpr=MLPRegressor(hidden_layer_sizes=(1000,),activation='relu',max_iter=500)
model_evaluation(mlpr,X_train,y_train,X_test,y_test)

第三种使用决策树回归模型

from sklearn.tree import DecisionTreeRegressor
dtr=DecisionTreeRegressor()
model_evaluation(dtr,X_train,y_train,X_test,y_test)

第三种极端随机森林
Extra_Tree是一种bagging方法,是基于极端随机树的迭代算法,与随机森林相比,模型会进一步减少方差。

from sklearn.ensemble import ExtraTreesRegressor
params = {'n_estimators': 50, 'random_state': np.random.RandomState(1)}
etr= ExtraTreesRegressor(**params)
model_evaluation(etr,X_train,y_train,X_test,y_test)

 

你可能感兴趣的:(算法)