Python&SPSS完成空气质量状况的指数(AQI)分析

记一次课程作业,利用所给数据,以AQI指数(空气质量状况指数)为因变量,其他指标为解释变量,建立线性回归分析模型,并形成分析报告。


题目要求

空气质量指数(air quality index,AQI是定量描述空气质量状况的指 数。为了更好地了解和人们身体健康息息相关的天气状况,本书模拟生成500条某地区天气数据,一行样本对应一天的天气。因变量为空气质量指 数:数值型变量。解释变量包括:星期:分类变量,包括星期一、星期二 等;最低气温:文本型变量,比如—5℃;最高气温:文本型变量,比如5℃;天气:分类变量,包括晴天、多云~睛、阴~多云、阴~小雨等,其 中“~”表示转,比如“晴~多云”表示晴转多云;风向:分类变量,包括 东风、西风、南风、北风、东南风、东北风、西南风、西北风等;风力:数 值型变量,1~5级。

以AQI为因变量,其他指标为解释变量,建立线性回归分析模型,并形成分析报告。

原始数据

第1章习题1
https://pan.baidu.com/s/1EKJyXBFGrNlsdqSjUE0LCA
提取码:yno6

注:SPSS以及python打开如果中文显示有问题,可以改一下后缀啥的txt,csv互换试试。

星期,最高,最低,天气,风向,风力,AQI
星期六,29,20,~雷阵雨,无持续,1,145
星期二,11,6,小雨~,,2,15
星期一,12,-3,,,3,177
星期五,28,18,,,2,90
星期日,-2,-10,,,3,36
················
················
················
星期六,16,3,多云,无持续,1,91
星期一,15,4,多云,,2,202
星期一,21,8,~,,3,39

(部分展示)

数据处理

数据总览

直观上来看,除了风力和AQI,其他数据都需要进行处理,用Pandas处理比较方便,首先用python对数据的总体情况进行了解。

import pandas as pd

data = pd.read_csv("第1章习题1.txt", sep=',', encoding='GBK')
print(data.head(10))
print('数据总览\n')

print(data.info())
print('数据类型预览\n')

print(data.describe())
print('数据情况\n')

print(data[data.isnull() == True].count())
print('数据缺失值检验\n')

# 统计总量
print('星期', len(data['星期'].value_counts()))
print('天气', len(data['天气'].value_counts()))
print('风向', len(data['风向'].value_counts()))

输出:

    星期   最高    最低     天气   风向  风力  AQI
0  星期六  2920℃  霾~雷阵雨  无持续   1  145
1  星期二  116℃   小雨~阴    北   2   15
2  星期一  12-3℃      晴    北   3  177
3  星期五  2818℃      阴    南   2   90
4  星期日  -2-10℃      晴    北   3   36
5  星期四  3017℃    晴~阴    南   2   63
6  星期六   7-2℃   多云~阴  无持续   1   39
7  星期五  2513℃  阵雨~多云    东   2   59
8  星期六   8-4℃    霾~晴  无持续   1  315
9  星期四   5-5℃   多云~晴   西北   3   28
数据总览

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 500 entries, 0 to 499
Data columns (total 7 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   星期      500 non-null    object
 1   最高      500 non-null    object
 2   最低      500 non-null    object
 3   天气      500 non-null    object
 4   风向      500 non-null    object
 5   风力      500 non-null    int64 
 6   AQI     500 non-null    int64 
dtypes: int64(2), object(5)
memory usage: 27.5+ KB
None
数据类型预览

               风力         AQI
count  500.000000  500.000000
mean     1.946000   96.690000
std      0.944918   63.743112
min      1.000000   15.000000
25%      1.000000   52.000000
50%      2.000000   82.000000
75%      3.000000  120.000000
max      5.000000  429.000000
数据情况

星期     0
最高     0
最低     0
天气     0
风向     0
风力     0
AQI    0
dtype: int64
数据缺失值检验

星期 7
天气 57
风向 9

结果分析:
缺失值:所有数据完整,数据量500
数据类型:只有“风力”、“AQI”为“int64”,其他均为“object”需要进行转换
类型数:天气类型数为57,而数据总量只有500,需要重点进行处理

“最高”&“最低”变量处理

    星期   最高    最低     天气   风向  风力  AQI
0  星期六  2920℃  霾~雷阵雨  无持续   1  145

原始数据中,变量后带有摄氏度标识,利用代码将他删掉并加入到新的数据集data2

data2 = pd.DataFrame()
data2['max_t'] = data['最高'].replace('℃','',regex=True)
data2['min_t'] = data['最低'].replace('℃','',regex=True)
print(data2)

输出:

    max_t min_t
0      29    20
1      11     6
2      12    -3
3      28    18
4      -2   -10
..    ...   ...
495    21    12
496    29    18
497    16     3
498    15     4
499    21     8

[500 rows x 2 columns]

“风向”变量处理

print(data['风向'].value_counts())
无持续    194124104
西南      3513
西北      11
东北      11
东南       5
西        3
Name: 风向, dtype: int64

在这里插入图片描述
在这里插入图片描述
Tableau展示的数据更直观,数据基本由‘北风’,‘南风’,‘无持续’组成,由于数据量不大,数据量第四多的“西南风”也只有35条,而“东南”,“西”只有个位数得数据量,进行回归意义不大,所以对于“风向“的处理方式为将数据分为四类:‘北风’,‘南风’,‘无持续’,‘风向_其他’。
由于需要进行线性回归分析,利用“get_dummies”方法将“风向”的四种变量转换为对应的矩阵,并添加到data2中。

代码实现:

data['风向'].replace(['西南','东','西北','东北','东南','西'],'风向_其他',inplace=True)
df_fx = pd.get_dummies(data['风向'])
print(df_fx.head(10))
data2 = data2.join(df_fx)
print(data2)

输出

   北  南  无持续  风向_其他
0  0  0    1      0
1  1  0    0      0
2  1  0    0      0
3  0  1    0      0
4  1  0    0      0
5  0  1    0      0
6  0  0    1      0
7  0  0    0      1
8  0  0    1      0
9  0  0    0      1
    max_t min_t  北  南  无持续  风向_其他
0      29    20  0  0    1      0
1      11     6  1  0    0      0
2      12    -3  1  0    0      0
3      28    18  0  1    0      0
4      -2   -10  1  0    0      0
..    ...   ... .. ..  ...    ...
495    21    12  0  0    1      0
496    29    18  0  0    1      0
497    16     3  0  0    1      0
498    15     4  0  1    0      0
499    21     8  1  0    0      0

[500 rows x 6 columns]

“星期”变量处理

在这里插入图片描述
在这里插入图片描述
“星期”变量分布均匀,不需要多作处理,直接和“风向”的处理方式一致,转换成矩阵。

df_xq = pd.get_dummies(data['星期'])
print(df_xq)
data2 = data2.join(df_xq)
print(data2)

输出

     星期一  星期三  星期二  星期五  星期六  星期四  星期日
0      0    0    0    0    1    0    0
1      0    0    1    0    0    0    0
2      1    0    0    0    0    0    0
3      0    0    0    1    0    0    0
4      0    0    0    0    0    0    1
..   ...  ...  ...  ...  ...  ...  ...
495    0    0    0    0    0    0    1
496    0    0    0    0    0    0    1
497    0    0    0    0    1    0    0
498    1    0    0    0    0    0    0
499    1    0    0    0    0    0    0

[500 rows x 7 columns]
    max_t min_t  北  南  无持续  风向_其他  星期一  星期三  星期二  星期五  星期六  星期四  星期日
0      29    20  0  0    1      0    0    0    0    0    1    0    0
1      11     6  1  0    0      0    0    0    1    0    0    0    0
2      12    -3  1  0    0      0    1    0    0    0    0    0    0
3      28    18  0  1    0      0    0    0    0    1    0    0    0
4      -2   -10  1  0    0      0    0    0    0    0    0    0    1
..    ...   ... .. ..  ...    ...  ...  ...  ...  ...  ...  ...  ...
495    21    12  0  0    1      0    0    0    0    0    0    0    1
496    29    18  0  0    1      0    0    0    0    0    0    0    1
497    16     3  0  0    1      0    0    0    0    0    1    0    0
498    15     4  0  1    0      0    1    0    0    0    0    0    0
499    21     8  1  0    0      0    1    0    0    0    0    0    0

[500 rows x 13 columns]

“天气”变量处理

在这里插入图片描述
通过数据总览我们知道天气变量一共有57种之多,Tableau也显示“天气”并不是集中为某几种,各种天气种类都占有一席之地。

    星期   最高    最低     天气   风向  风力  AQI
0  星期六  2920℃  霾~雷阵雨  无持续   1  145
1  星期二  116℃   小雨~阴    北   2   15

我们同时也观察到有天气几乎都是复合型天气,由两种天气组成,我们尝试着把他拆开,继续观察。

from collections import Counter

c = data['天气'].apply(lambda x: x.split('~'))

lists = []
for i in c:
    for ii in i:
        lists.append(ii)
counts = Counter(lists)
for k,v in counts.items():
    print(k,v)

print("总数:", len(counts))

输出

45
雷阵雨 47
小雨 2896264
多云 225
阵雨 304
雨夹雪 5
小到中雨 3
中到大雨 2
中雨 4
小雪 4
大到暴雨 1
大雨 2
大雪 1
暴雨 1
总数: 17

我们可以看到“天气”种类由原来的57种变成了现在的17种,同时也可以观察到有多种同类的变量:比如“大雨”、“小雨”、“中雨”。我们可以将他们按照一定规则量化,来看成一种天气,如:

小雨 1 小雪 1
小到中雨 2
中雨 3 雨夹雪 2
中到大雨 4
大雨 5 大雪 3
大到暴雨 6
暴雨 7
data3 = pd.DataFrame()
data3['晴'] = c.apply(lambda x: 1 if '晴' in x else 0)
data3['多云'] = c.apply(lambda x: 1 if '多云' in x else 0)
data3['阴'] = c.apply(lambda x: 1 if '阴' in x else 0)
data3['雷阵雨'] = c.apply(lambda x: 1 if '雷阵雨' in x else 0)
data3['霾'] = c.apply(lambda x: 1 if '霾' in x else 0)
data3['雾'] = c.apply(lambda x: 1 if '雾' in x else 0)
data3['阵雨'] = c.apply(lambda x: 1 if '阵雨' in x else 0)
dict1={
    
    '小雨':1,'小到中雨':2,'中雨':3,'中到大雨':4,'大雨':5,'大到暴雨':6,'暴雨':7}
dict2={
    
    '小雪':1,'雨夹雪':2,'大雪':3}

def d_dict1(x):
    m = 0
    for i in x:
        m1 = dict1.get(i)
        if type(m1) == int:
            if m1 > m:
                m = m1
    return m

def d_dict2(x):
    m = 0
    for i in x:
        m1 = dict2.get(i)
        if type(m1) == int:
            if m1 > m:
                m = m1
    return m

data3['雨'] = c.apply(d_dict1)
data3['雪'] = c.apply(d_dict2)

print(data3)
data2 = data2.join(data3)
print(data2)

输出

     晴  多云  阴  雷阵雨  霾  雾  阵雨  雨  雪
0    0   0  0    1  1  0   0  0  0
1    0   0  1    0  0  0   0  1  0
2    1   0  0    0  0  0   0  0  0
3    0   0  1    0  0  0   0  0  0
4    1   0  0    0  0  0   0  0  0
..  ..  .. ..  ... .. ..  .. .. ..
495  1   0  0    0  1  0   0  0  0
496  1   0  0    0  0  0   0  0  0
497  0   1  0    0  0  0   0  0  0
498  0   1  0    0  0  0   0  0  0
499  1   0  1    0  0  0   0  0  0

[500 rows x 9 columns]
    max_t min_t  北  南  无持续  风向_其他  星期一  星期三  星期二  ...  晴  多云  阴  雷阵雨  霾  雾  阵雨  雨  雪
0      29    20  0  0    1      0    0    0    0  ...  0   0  0    1  1  0   0  0  0
1      11     6  1  0    0      0    0    0    1  ...  0   0  1    0  0  0   0  1  0
2      12    -3  1  0    0      0    1    0    0  ...  1   0  0    0  0  0   0  0  0
3      28    18  0  1    0      0    0    0    0  ...  0   0  1    0  0  0   0  0  0
4      -2   -10  1  0    0      0    0    0    0  ...  1   0  0    0  0  0   0  0  0
..    ...   ... .. ..  ...    ...  ...  ...  ...  ... ..  .. ..  ... .. ..  .. .. ..
495    21    12  0  0    1      0    0    0    0  ...  1   0  0    0  1  0   0  0  0
496    29    18  0  0    1      0    0    0    0  ...  1   0  0    0  0  0   0  0  0
497    16     3  0  0    1      0    0    0    0  ...  0   1  0    0  0  0   0  0  0
498    15     4  0  1    0      0    1    0    0  ...  0   1  0    0  0  0   0  0  0
499    21     8  1  0    0      0    1    0    0  ...  1   0  1    0  0  0   0  0  0

[500 rows x 22 columns]

Process finished with exit code 0

数据分析

多重共线性

在这里插入图片描述

在Tableau中将最高气温放在横轴,最低气温作为竖轴,从图片能直观得感受到散点图呈现线性分布,可能会对之后得回归产生影响,可以假设AQI可能主要和温差有关,而不是最高温度或者最低温度有关,将这个变量加入后,将处理后的数据保存,进行建模。

新建“温差”变量

本来想直接在data2中操作,直接将“max_t”与“min_t”相减,但是报错说数据结构不对,又想直接把这两列转换为"int"类型,但是又报错说有减号存在,无法转换。最后不知道怎么办,只好先把他保存一次,然后重新读取一次,自动识别到为"int"类型,不得已出此下策,如果这步有解决方案,欢迎大佬们评论指出。

data2.to_csv('清洗后.txt', encoding='utf-8')
new_data = pd.read_csv("清洗后.txt", sep=',', encoding='utf-8',index_col=0)
new_data['温差'] = new_data['max_t']-new_data['min_t']
new_data['AQI'] = data['AQI']
print(new_data)
new_data.to_csv('分析后.csv', encoding='UTF-8')

输出

     max_t  min_t  北  南  无持续  风向_其他  星期一  星期三  ...  雷阵雨  霾  雾  阵雨  雨  雪  温差  AQI
0       29     20  0  0    1      0    0    0  ...    1  1  0   0  0  0   9  145
1       11      6  1  0    0      0    0    0  ...    0  0  0   0  1  0   5   15
2       12     -3  1  0    0      0    1    0  ...    0  0  0   0  0  0  15  177
3       28     18  0  1    0      0    0    0  ...    0  0  0   0  0  0  10   90
4       -2    -10  1  0    0      0    0    0  ...    0  0  0   0  0  0   8   36
..     ...    ... .. ..  ...    ...  ...  ...  ...  ... .. ..  .. .. ..  ..  ...
495     21     12  0  0    1      0    0    0  ...    0  1  0   0  0  0   9  163
496     29     18  0  0    1      0    0    0  ...    0  0  0   0  0  0  11   85
497     16      3  0  0    1      0    0    0  ...    0  0  0   0  0  0  13   91
498     15      4  0  1    0      0    1    0  ...    0  0  0   0  0  0  11  202
499     21      8  1  0    0      0    1    0  ...    0  0  0   0  0  0  13   39

[500 rows x 24 columns]

回归建模

数据导入

经过之前的数据处理得到新的数据集“分析后.csv”
利用SPSS进行多元线性回归分析
如果导入数据乱码,可以尝试更改上述代码保存的最后形式,如

new_data.to_csv('分析后.csv', encoding='UTF-8')
new_data.to_csv('分析后.csv', encoding='GBK')
new_data.to_csv('分析后.txt', encoding='UTF-8')
new_data.to_csv('分析后.txt', encoding='GBK')

一路默认下一步,小数点句号,分隔符逗号,最后变量名“V1”选择不导入就行。数据导入后如下图:

在这里插入图片描述
在这里插入图片描述

SPSS线性回归操作

欢迎参考
https://blog.csdn.net/weixin_44255182/article/details/108932498
分析——回归——线性
除了因变量,其他全部放自变量中
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

SPSS结果分析

模型概要

在这里插入图片描述
用步进的方式将变量一个一个加入建立模型,并计算R²,从模型1到模型6,每个变量加入后都使得R²增加,说明后一个模型都优于前一个模型,最终我们选择第六个模型,也就是包括了:雾、霾、晴、最低温度,最高温度,以及无持续风。

模型比较

在这里插入图片描述
模型6回归平方和最大,解释自变量的部分最多,并且所有模型显著性均小于0.05,说明所有模型都能很好得解释因变量。

排除的变量

在这里插入图片描述
在这里插入图片描述
这些变量在加入后,由于显著性均大于0.05,说明接受原假设,认为该变量系数为0,即不影响因变量,将其排除。不过这温差啥意思,我也看不懂….

共线性诊断

在这里插入图片描述
在这里插入图片描述
有没有大佬看得懂这个分析结果的,麻烦也留言一下

异常个案诊断

在这里插入图片描述
显示了七个预测异常个案,个案号为92,124,150,251,338,465。去看看这几个个案。

print(data.iloc[[91,123,149,250,337,464]])
      星期   最高   最低    天气     风向  风力  AQI
91   星期三   3-3℃     霾    无持续   1  429
123  星期六   9-2℃     晴      北   2  303
149  星期日  197℃  多云~阴  风向_其他   2  278
250  星期六  1712℃    小雨    无持续   1  246
337  星期三   6-5℃     霾      北   2  365
464  星期二   85℃     霾      北   3  401

好像也没看出个啥特别的原因。
在这里插入图片描述
在这里插入图片描述

模型回归系数

在这里插入图片描述
在这里插入图片描述
系数图表中可以看到min_t和max_t的VIF值较大,分别为20.57,18.93(远大于5),说明最高温度和最低温度之间确实存在共线性。

所有系数显著性都小于0.05,说明拒绝系数为0的原假设。

最终模型方程为:
AQI=
+81.090(常数)
+101.777 * 霾
-31.384* 晴
+101.929 * 雾
-2.995 * 最小温度
+2.355 * 最大温度
+10.452 * 是否有持续风

残差检验

在这里插入图片描述
残差直方图比较正常,基本符合正态分布
在这里插入图片描述
在这里插入图片描述
残差图显示,大部分数据预测准确,残差集中分布在(0,0)点向周围扩散,大部分数据在【-2,2之间】,没有趋势性变化,不过仍有,部分数据不能很好得预测,残差分布在远离正常值的【2,6】之间。对这三团有其他理解的也欢迎指教。

模型的不足

  1. 最高温度和最低温度存在共线性,需要去去除其中一个变量,重新建模。
  2. 由于将天气一分为二,不同的天气之间可能有一定相关性,比如雾霾基本都是成对出现,模型结果是雾、霾分别影响了AQI,可能只有霾是影响AQI的因素,但是由于雾霾都是成对出现,将他们划分开后,导致这个结果,可以继续研究。
  3. 模型中并没有星期的结果,可以继续考虑将时间划分为工作日和非工作日,观察AQI是否受影响

第二次数据处理

“星期”变量处理

将之前的星期变量变为”休息日“和”工作日“,将所有的”休息日“标记为1,”工作日“标记为0。考虑到之前的处理方式,我们只需要把”星期六“和”星期天“的加起来就行了。

import pandas as pd

data = pd.read_csv("分析后.csv", sep=',', encoding='GBK', index_col=0)
data["休息日"] = data["星期六"]+data["星期日"]
print(data)
data.to_csv('第二次处理.csv', encoding='utf-8')

输出

     max_t  min_t  北  南  无持续  风向_其他  星期一  星期三  ...  霾  雾  阵雨  雨  雪  温差  AQI  休息日
0       29     20  0  0    1      0    0    0  ...  1  0   0  0  0   9  145    1
1       11      6  1  0    0      0    0    0  ...  0  0   0  1  0   5   15    0
2       12     -3  1  0    0      0    1    0  ...  0  0   0  0  0  15  177    0
3       28     18  0  1    0      0    0    0  ...  0  0   0  0  0  10   90    0
4       -2    -10  1  0    0      0    0    0  ...  0  0   0  0  0   8   36    1
..     ...    ... .. ..  ...    ...  ...  ...  ... .. ..  .. .. ..  ..  ...  ...
495     21     12  0  0    1      0    0    0  ...  1  0   0  0  0   9  163    1
496     29     18  0  0    1      0    0    0  ...  0  0   0  0  0  11   85    1
497     16      3  0  0    1      0    0    0  ...  0  0   0  0  0  13   91    1
498     15      4  0  1    0      0    1    0  ...  0  0   0  0  0  11  202    0
499     21      8  1  0    0      0    1    0  ...  0  0   0  0  0  13   39    0

[500 rows x 25 columns]

第二次建模

第二次建模我们不加入”星期“变量,加入新变量”休息日“进行分析

SPSS分析

在这里插入图片描述
在这里插入图片描述
一样的结果,”休息日“显著性为0.249,大于0.05,接受原假设,认为”休息日“系数为0。

模型总结

最终模型为AQI=81.090+101.777 * 是否有霾-31.384 * 是为晴+101.929 * 是否有雾-2.995 * 最小温度+2.355 * 最大温度+10.452 * 是否无持续风

其中我们模型中并没有星期的信息,说明星期几对AQI影响不大,也就是说不同的日期出门差别不大。

模型中并没有风力大小的因子,也没有北风,南风。说明什么方向的风对AQI影响不大,风力的大小也对AQI影响不大,但是当天如果无持续风,空气质量会略微变差,说明在有风的天气空气质量会好一些。

影响AQI最重要的就是天气,可以看到如果当天有雾、霾空气质量会显著降低,这和我们的经验相符。如果当天是晴天,则空气质量较好。

关于温度,由于最后检验结果,最高温度和最低温度存在线性关系,不作分析。

猜你喜欢

转载自blog.csdn.net/weixin_44255182/article/details/109093765