python空气质量分析与预测_干货!如何用 Python+KNN 算法实现城市空气质量分析与预测?...

原标题:干货!如何用 Python+KNN 算法实现城市空气质量分析与预测?

作者 | 李秋键

责编 | 伍杏玲

封图 | CSDN 付费下载自东方 IC

出品 | CSDN(ID:CSDNnews)

随着中国工业和科技的发展,中国的一些发达城市的空气质量问题变得越来越严重,其中最为严重的便是PM2.5带来的恶劣环境问题。

本文在根据网络公开空气质量数据的基础上进行爬取相关数据,主要针对环境较为恶劣的城市,天津、北京、广州等几个城市,尤其是针对天津的质量数据进行对比分析。在分析的基础上得出空气质量变化情况,提出一些意见。并借助机器学习算法根据数据预测空气质量,以达到分析预测的典型大数据分析模式效果。

整体分析的流程图如下:

实验前的准备

1.1 数据获取

我们这里所得到的数据来源于网络公开的空气质量数据,数据来源于“天气后报”网站,网址为:http://www.tianqihoubao.com/aqi/tianjin.html。网址内容如下图可见:

图1-1 网址数据图

整个数据的获取使用python进行爬取。流程如下:

(1) 导入爬虫所需要的的库:

在air_tianjin_2019.py程序中。

其中Requests 是用Python语言编写,基于urllib,采用 Apache2 Licensed开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。

其中BeautifulSoup库是一个灵活又方便的网页解析库,处理高效,支持多种解析器。利用它就不用编写正则表达式也能方便的实现网页信息的抓取

对应代码如下:

importtime

importrequests

frombs4 importBeautifulSoup

(2)为了防止网站的反爬机制,我们设定模拟浏览器进行访问获取数据:

headers= { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

(3)然后获取2019年全年的空气质量数据:

fori inrange( 1, 13):

time. sleep( 5)

url = 'http://www.tianqihoubao.com/aqi/tianjin-2019'+ str( "%02d"% i) + '.html'

response = requests. get(url=url, headers=headers)

soup = BeautifulSoup(response.text, 'html.parser')

tr = soup.find_all( 'tr')

1.2 数据预处理

如果仅仅是从网站上得到的数据会有一些标签等干扰项,我们针对一些标签进行去除即可:

forj intr[ 1:]:

td = j.find_all( 'td')

Date= td[ 0].get_text.strip

Quality_grade = td[ 1].get_text.strip

AQI = td[ 2].get_text.strip

AQI_rank = td[ 3].get_text.strip

PM = td[ 4].get_text

withopen( 'air_tianjin_2019.csv', 'a+', encoding= 'utf-8-sig') asf:

f.write( Date+ ','+ Quality_grade + ','+ AQI + ','+ AQI_rank + ','+ PM + 'n')

最终爬取下来的部分数据如下:

表1-1 部分天津爬取数据表

这几个数据分别对应着AQI指数、当天AQI排名和PM2.5值

数据分析

这里的数据分析主要通过可视化的方法得到图像来进行分析。

(1) 天津AQI全年走势图

代码在air_tianjin_2019_AQI.py中

通过导入pyecharts 库来进行绘制走势图

首先通过已经获取到的数据进行读取:

df= pd.read_csv( 'air_tianjin_2019.csv', header=None, names=[ "Date", "Quality_grade", "AQI", "AQI_rank", "PM"])

然后获取日期和AQI数据,储存在列表变量中,以方便绘制图像:

attr= df[ 'Date']v1 = df[ 'AQI']

接着定义标题,绘制曲线并保存为网页即可:

line = Line( "2019年天津AQI全年走势图", title_pos= 'center', title_top= '18', width= 800, height= 400)

line. add( "", attr, v1, mark_line=[ 'average'], is_fill=True, area_color= "#000", area_opacity= 0.3, mark_point=[ "max", "min"], mark_point_symbol= "circle", mark_point_symbolsize= 25)

line.render( "2019年天津AQI全年走势图.html")

最终的效果图如下可见

图2-2 2019年天津AQI全年走势图

根据图2-2可知,在2019年度,天津的空气质量峰值分别是在1月、2月、11月和12月,即主要集中在春冬季,考虑到可能是春冬季通风较差,且节日较多,过多的节日烟花和汽车人员流动造成了空气质量变差。

(2)天津月均AQI走势图

air_tianjin_2019_AQI_month.py

为了体现出每月的平均空气质量变化,我们绘制了月均走势图。

首先同样的是读取数据:

df= pd.read_csv( 'air_tianjin_2019.csv', header=None, names=[ "Date", "Quality_grade", "AQI", "AQI_rank", "PM"])

接着获取日期和空气质量数据,并加以处理,去除日期中间的“-”:

dom = df [['Date', 'AQI']]

list1 = []

forj indom[ 'Date']:

time= j.split( '-')[ 1]

list1.append( time)

df[ 'month'] = list1

接着计算每月空气质量的平均值

month_message = df.groupby(['month'])

month_com = month_message['AQI'].agg(['mean'])

month_com.reset_index(inplace=True)

month_com_last = month_com.sort_index

attr = [ "{}".format(str(i) + '月') for i in range(1, 13)]

v1 = np.array(month_com_last['mean'])

v1 = [ "{}".format(int(i)) for i in v1]

然后绘制走势图:

line = Line( "2019年天津月均AQI走势图", title_pos= 'center', title_top= '18', width= 800, height= 400)

line. add( "", attr, v1, mark_point=[ "max", "min"])

line.render( "2019年天津月均AQI走势图.html")

最终的效果图如下可见:

图2-3 2019年天津月均AQI走势图

(3)天津季度AQI箱形图

代码在air_tianjin_2019_AQI_season.py中

绘制天津季度空气质量箱型图,步骤如下:

读取爬取下来的数据:

df= pd.read_csv( 'air_tianjin_2019.csv', header=None, names=[ "Date", "Quality_grade", "AQI", "AQI_rank", "PM"])

接着按照月份分季,可以分为四个季度:

dom = df [['Date', 'AQI']]

data = [[], [], [], []]

dom1, dom2, dom3, dom4 = data

fori, j inzip(dom[ 'Date'], dom[ 'AQI']):

time= i.split( '-')[ 1]

iftimein[ '01', '02', '03']:

dom1.append(j)

elif timein[ '04', '05', '06']:

dom2.append(j)

elif timein[ '07', '08', '09']:

dom3.append(j)

else:

dom4.append(j)

然后定义箱型图的标题,横纵坐标等绘制箱型图:

boxplot = Boxplot( "2019年天津季度AQI箱形图", title_pos='center', title_top='18', width=800, height=400)

x_axis = ['第一季度', '第二季度', '第三季度', '第四季度']

y_axis = [dom1, dom2, dom3, dom4]

_yaxis = boxplot.prepare_data(y_axis)

boxplot.add( "", x_axis, _yaxis)

boxplot.render( "2019年天津季度AQI箱形图.html")

最终得到绘制的箱型图如下可见:

图2-4 2019年天津季度AQI箱形图

KNN算法预测

整体的代码流程分为两个部分,一部分是建立test.py程序用来将CSV文件转为符合标准的TXT数据存储;另一部分是K均值聚类的数据分类。

(1) 数据生成TXT

代码在test.py中

首先读入数据,存出入列表为x何y。同时因为y的值为汉字,需要转换为数字:

# 文件的名字

FILENAME1 = "air_tianjin_2019.csv"

# 禁用科学计数法

pd.set_option( 'float_format', lambdax: '%.3f'% x)

np.set_printoptions(threshold=np.inf)

# 读取数据

data = pd.read_csv(FILENAME1)

rows, clos = data.shape

# DataFrame转化为array

DataArray = data.values

Y=[]

y = DataArray[:, 1]

fori iny:

ifi== "良":

Y.append( 0)

ifi== "轻度污染":

Y.append( 1)

ifi== "优":

Y.append( 2)

ifi== "严重污染":

Y.append( 3)

ifi== "重度污染":

Y.append( 4)

print(Y)

print(len(y))

X = DataArray[:, 2: 5]

print(X[ 1])

然后将存储的数据写入TXT,其中要注意换行和加“,”:

fori inrange( len(Y)):

f= open( "data.txt", "a+")

forj inrange( 3):

f. write(str(X[i][j])+ ",")

f. write(str(Y[i])+ "n")

print( "data.txt数据生成")

(2)K均值聚类

代码在KNearestNeighbor.py中。

首先是读取数据:

def loadDataset(self,filename, split, trainingSet, testSet): # 加载数据集 split以某个值为界限分类train和test

with open(filename, 'r') as csvfile:

lines = csv.reader(csvfile) #读取所有的行

dataset = list(lines) #转化成列表

for x in range(len(dataset)-1):

for y in range(3):

dataset[ x][ y] = float(dataset[ x][ y])

if random.random < split:# 将所有数据加载到 train和 test中

trainingSet.append( dataset[ x])

else:

testSet.append( dataset[ x])

定义计算距离的函数

defcalculateDistance( self,testdata, traindata, length): # 计算距离

distance = 0# length表示维度 数据共有几维

forx inrange(length):

distance += pow((int(testdata[x])-traindata[x]), 2)

returnmath.sqrt(distance)

对每个数据文档测量其到每个质心的距离,并把它归到最近的质心的类。

defgetNeighbors(self,trainingSet, testInstance, k):# 返回最近的k个边距

distances = []

length = len(testInstance) -1

forx inrange(len(trainingSet)): #对训练集的每一个数计算其到测试集的实际距离

dist = self.calculateDistance(testInstance, trainingSet[x], length)

print( '训练集:{}-距离:{}'.format(trainingSet[x], dist))

distances.append((trainingSet[x], dist))

distances.sort(key=operator.itemgetter( 1)) # 把距离从小到大排列

print(distances)

neighbors = []

forx inrange(k): #排序完成后取前k个距离

neighbors.append(distances[x][ 0])

print(neighbors)

returnneighbors

决策函数,根据少数服从多数,决定归类到哪一类:

def getResponse(self,neighbors): # 根据少数服从多数,决定归类到哪一类

classVotes = {}

for x in range(len(neighbors)):

response = neighbors[ x][ -1] # 统计每一个分类的多少

if response in classVotes:

classVotes[response] += 1

else:

classVotes[response] = 1

print(classVotes.items)

sortedVotes = sorted(classVotes.items, key=operator.itemgetter(1), reverse=True) #reverse按降序的方式排列

return sortedVotes[ 0][ 0]

计算模型准确度

def getAccuracy(self,testSet, predictions): # 准确率计算

correct = 0

for x in range(len(testSet)):

if testSet[ x][ -1] == predictions[x]: #predictions是预测的和testset实际的比对

correct += 1

print('共有{}个预测正确,共有{}个测试数据'.format(correct,len(testSet)))

return (correct/float(len(testSet)))*100.0

接着整个模型的训练,种子数定义等等:

defRun(self):

trainingSet = []

testSet = []

split = 0.75

self.loadDataset( r'data.txt', split, trainingSet, testSet) #数据划分

print( 'Train set: '+ str(len(trainingSet)))

print( 'Test set: '+ str(len(testSet)))

#generate predictions

predictions = []

k = 5# 取最近的5个数据

# correct = []

forx inrange(len(testSet)): # 对所有的测试集进行测试

neighbors = self.getNeighbors(trainingSet, testSet[x], k) #找到5个最近的邻居

result = self.getResponse(neighbors) # 找这5个邻居归类到哪一类

predictions.append(result)

# print('predictions: ' + repr(predictions))

# print('>predicted=' + repr(result) + ', actual=' + repr(testSet[x][-1]))

# print(correct)

accuracy = self.getAccuracy(testSet,predictions)

print( 'Accuracy: '+ repr(accuracy) + '%')

最终模型的准确度为90%。

图2-10 模型运行结果图

源码地址:

https://pan.baidu.com/s/1Vcc_bHQMHmQpe-F6A-mFdQ

提取码:qvy7

作者简介:李秋键,CSDN博客专家,CSDN达人课作者。硕士在读于中国矿业大学,开发有taptap竞赛获奖等。返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值