空氣質量分析
由於霧霾問題,全社會都很關注空氣質量,政府也花了很多錢力圖改善空氣質量。我們作為城市市民經常要問:我們城市的空氣質量到底怎樣?這幾年我們城市的空氣質量是在改善還是惡化?我們城市的空氣質量與其他城市相比,是更好還是更差?
官方媒體一般都是說:我們的空氣質量在改善,但有資料證明嗎?官方資料可信嗎?我們心存疑慮。所以,作為資料狗,還是自己動手吧。
PM2.5是最近幾年特別熱議的空氣質量指標,這要歸功於美帝大使館哦。美國駐華使館和領館自己檢測PM2.5資料並且在官網釋出,這才讓國人知道了這個指標,後來國內官方也開始公佈這個指標了。
言歸正傳,差點忘了,這是一篇Python技術貼。回到這篇文章的主題:用Python做資料分析。我生活在廣州,當然以我大廣州為分析目標了。
資料來源:美國駐華使館的空氣質量檢測資料, [ http://www.stateair.net/web/historical/1/1.html
](http://www.stateair.net/web/historical/1/1.html) 包含以下欄位:
其中,PM2.5數值所代表的空氣質量評價如下表1-1所示:
在此基礎上,如果指數大於500,就是大家戲稱為“爆表”
問題:
一.廣州的空氣質量總體如何?
二.廣州最近兩年的空氣質量是否有改善?
三.廣州北京兩地的空氣質量對比
這幾個問題其實比較大而空,要落實到具體的指標和維度。從我們掌握的以上資料出發,可以從以下幾個指標和維度分析:
1.2016年全年來看,空氣質量較好(PM2.5<=100)的天數佔比是多少?2015年相比2016年的對比?北京與各自的對比如何?
2.2016年全年來看,空氣質量最嚴重(PM2.5>300)的天數佔比是多少?2015年相比2016年的對比?北京與各自的對比如何?
3.2016年全年來看,空氣質量與季節(月份)的變化關係是什麼?
4.2016年與2015年同時間點對比,空氣質量較好和較差的次數分別是多少?
5.2016年廣州與北京同時間點對比,空氣質量較好和較差的次數分別是多少?
通過以上維度分析,可以基本對前面的三大問題得出大致的判斷。當然,有興趣的童鞋可以根據原始資料出發,從更多的維度進行分析哦。
下面就開始進入資料集吧。
1. 資料集下載、讀取和清洗
從美駐華使館官網下載了廣州、北京兩個城市,2015年和2016年的PM2.5資料。分別是這四個檔案:
Beijing_2015_HourlyPM25_created20160201.csv
Beijing_2016_HourlyPM25_created20170201.csv
Guangzhou_2015_HourlyPM25_created20170201.csv
Guangzhou_2016_HourlyPM25_created20170201.csv
為了簡化工作,每個檔案只保留這幾個欄位:Year、Month、Day、Hour、Value和QC
name,用Excel刪掉其他的欄位和文字,千萬注意要保留表頭哦。
經過大致觀察,可以發現以下幾點:
- 資料以csv格式儲存,每年1個檔案
- 每個小時一條檢測資料
首先引入必要的Python包
In [1]:
import unicodecsv
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sb
%matplotlib inline
從csv檔案中讀入資料
pandas是Python中常用的資料分析工具,包含了大量簡便的資料分析處理方法。本文通過這個例子,展現了幾個常用的pandas使用方法。
其中,使用pandas可以很方便地從csc檔案中讀取資料,儲存在DataFrame物件中,方法如下:
In [2]:
# 從csv中讀取北京2015年pm2.5資料,儲存在DataFrame中
df_bj2015 = pd.read_csv('data/Beijing_2015_HourlyPM25_created20160201.csv')
# 重新設定各個欄位的名稱
df_bj2015.columns=['Year','Month','Day','Hour','Value','QC']
資料探索和清洗
拿到資料集,並且匯入了DataFrame物件後,我們需要對資料進行觀察,看看是否有缺失和錯誤的情況,並且對資料集進行必要的清洗處理,以便後續得到更準確的分析結果。
In [3]:
# 檢視DataFrame中的前幾條資料
df_bj2015.head()
Out[3]:
Year | Month | Day | Hour | Value | QC |
---|---|---|---|---|---|
0 | 2015 | 1 | 1 | 0 | 22 |
1 | 2015 | 1 | 1 | 1 | 9 |
2 | 2015 | 1 | 1 | 2 | 9 |
3 | 2015 | 1 | 1 | 3 | 13 |
4 | 2015 | 1 | 1 | 4 | 10 |
In [4]:
# DataFrame的簡要描述
df_bj2015.describe()
Out[4]:
Year | Month | Day | Hour | Value |
---|---|---|---|---|
count | 8760.0 | 8760.000000 | 8760.000000 | 8760.000000 |
8760.000000
mean | 2015.0 | 6.526027 | 15.720548 | 11.500114 | 71.658904
std | 0.0 | 3.448048 | 8.796749 | 6.922433 | 139.751292
min | 2015.0 | 1.000000 | 1.000000 | 0.000000 | -999.000000
25% | 2015.0 | 4.000000 | 8.000000 | 5.750000 | 21.000000
50% | 2015.0 | 7.000000 | 16.000000 | 11.500000 | 53.000000
75% | 2015.0 | 10.000000 | 23.000000 | 17.250000 | 108.000000
max | 2015.0 | 12.000000 | 31.000000 | 23.000000 | 722.000000
從簡要描述中,可以看出Value欄位(pm2.5的值)最小值是-999,正常來說,PM2.5的值不會小於零的,這說明有些觀測值是缺失或者記錄錯誤。我們可以計算一下其中有多少Value<0的記錄:
In [5]:
len(df_bj2015.ix[df_bj2015.Value<0, :])
Out[5]:
97
[/code]
全年8000多條資料中,只有97條記錄缺失或錯誤,所以把這97條記錄刪除,對整個分析影響不大。以下把缺失或錯誤的記錄刪除:
In [6]:
```code
# 把錯誤值置為空值
df_bj2015.loc[df_bj2015.Value<0,'Value']=np.nan
# 刪除空值記錄
df_bj2015.dropna(inplace=True)
再用describe方法看看資料集的概況:
In [7]:
df_bj2015.describe()
Out[7]:
Year | Month | Day | Hour | Value |
---|---|---|---|---|
count | 8663.0 | 8663.000000 | 8663.000000 | 8663.000000 |
8663.000000
mean | 2015.0 | 6.538728 | 15.674939 | 11.494055 | 82.733810
std | 0.0 | 3.448080 | 8.787195 | 6.938605 | 88.556186
min | 2015.0 | 1.000000 | 1.000000 | 0.000000 | 0.000000
25% | 2015.0 | 4.000000 | 8.000000 | 5.000000 | 21.000000
50% | 2015.0 | 7.000000 | 16.000000 | 11.000000 | 54.000000
75% | 2015.0 | 10.000000 | 23.000000 | 18.000000 | 109.000000
max | 2015.0 | 12.000000 | 31.000000 | 23.000000 | 722.000000
可以看出,Value欄位最小值不再為負數,這樣的資料基本可信。
另外,我們還要為資料集增加一個欄位,根據前面表1-1的劃分方法,把pm2.5的測量值Value,轉換為空氣質量等級。
首先,我們先寫一個函式,通過pm2.5測量值對應的空氣質量等級。
In [8]:
df_bj2015.describe()
Out[8]:
Year | Month | Day | Hour | Value |
---|---|---|---|---|
count | 8663.0 | 8663.000000 | 8663.000000 | 8663.000000 |
8663.000000
mean | 2015.0 | 6.538728 | 15.674939 | 11.494055 | 82.733810
std | 0.0 | 3.448080 | 8.787195 | 6.938605 | 88.556186
min | 2015.0 | 1.000000 | 1.000000 | 0.000000 | 0.000000
25% | 2015.0 | 4.000000 | 8.000000 | 5.000000 | 21.000000
50% | 2015.0 | 7.000000 | 16.000000 | 11.000000 | 54.000000
75% | 2015.0 | 10.000000 | 23.000000 | 18.000000 | 109.000000
max | 2015.0 | 12.000000 | 31.000000 | 23.000000 | 722.000000
In [9]:
def get_grade(value):
if value <= 50 and value>=0:
return 'Good'
elif value <= 100:
return 'Moderate'
elif value <= 150:
return 'Unhealthy for Sensi'
elif value <= 200:
return 'Unhealthy'
elif value <= 300:
return 'Very Unhealthy'
elif value <= 500:
return 'Hazardous'
elif value > 500:
return 'Beyond Index' # 爆表了
else:
return None # 輸入值無效
以下使用DataFrame的apply函式,增加一個欄位‘Grade’,並且根據‘Value’欄位的值,呼叫前面的轉換函式,為‘Grade’欄位賦值。
In [10]:
df_bj2015.loc[:, 'Grade'] = df_bj2015['Value'].apply(get_grade)
再來看看增加欄位後的資料集
In [11]:
df_bj2015.head()
Out[11]:
Year | Month | Day | Hour | Value | QC | Grade |
---|---|---|---|---|---|---|
0 | 2015 | 1 | 1 | 0 | 22.0 | Valid |
1 | 2015 | 1 | 1 | 1 | 9.0 | Valid |
2 | 2015 | 1 | 1 | 2 | 9.0 | Valid |
3 | 2015 | 1 | 1 | 3 | 13.0 | Valid |
4 | 2015 | 1 | 1 | 4 | 10.0 | Valid |
經過以上的處理,我們就把北京2015年的PM2.5資料集處理完成了。對於其他三個表格,我們都採取類似的處理。
In [12]:
# 從csv中讀取北京2016年pm2.5資料,儲存在DataFrame中
df_bj2016 = pd.read_csv('data/Beijing_2016_HourlyPM25_created20170201.csv')
# 重新設定各個欄位的名稱
df_bj2016.columns=['Year','Month','Day','Hour','Value','QC']
# 對錯誤和缺失值賦為空值
df_bj2016.loc[df_bj2016.Value<0,'Value']=np.nan
# 刪除空值記錄
df_bj2016.dropna(inplace=True)
#增加空氣質量等級欄位‘Grade’
df_bj2016.loc[:, 'Grade'] = df_bj2016['Value'].apply(get_grade)
In [13]:
df_bj2016.head()
Out[13]:
Year | Month | Day | Hour | Value | QC | Grade |
---|---|---|---|---|---|---|
0 | 2016 | 1 | 1 | 0 | 231.0 | Valid |
1 | 2016 | 1 | 1 | 1 | 239.0 | Valid |
2 | 2016 | 1 | 1 | 2 | 205.0 | Valid |
3 | 2016 | 1 | 1 | 3 | 167.0 | Valid |
4 | 2016 | 1 | 1 | 4 | 132.0 | Valid |
In [14]:
# 從csv中讀取廣州2016年pm2.5資料,儲存在DataFrame中
df_gz2016 = pd.read_csv('data/Guangzhou_2016_HourlyPM25_created20170201.csv')
# 重新設定各個欄位的名稱
df_gz2016.columns=['Year','Month','Day','Hour','Value','QC']
# 對錯誤和缺失值賦為空值
df_gz2016.loc[df_gz2016.Value<0,'Value']=np.nan
# 刪除空值記錄
df_gz2016.dropna(inplace=True)
#增加空氣質量等級欄位‘Grade’
df_gz2016.loc[:, 'Grade'] = df_gz2016['Value'].apply(get_grade)
In [15]:
df_gz2016.head()
Out[15]:
Year | Month | Day | Hour | Value | QC | Grade |
---|---|---|---|---|---|---|
0 | 2016 | 1 | 1 | 0 | 55.0 | Valid |
1 | 2016 | 1 | 1 | 1 | 58.0 | Valid |
2 | 2016 | 1 | 1 | 2 | 59.0 | Valid |
3 | 2016 | 1 | 1 | 3 | 58.0 | Valid |
4 | 2016 | 1 | 1 | 4 | 51.0 | Valid |
In [16]:
# 從csv中讀取廣州2015年pm2.5資料,儲存在DataFrame中
df_gz2015 = pd.read_csv('data/Guangzhou_2015_HourlyPM25_created20160201.csv')
# 重新設定各個欄位的名稱
df_gz2015.columns=['Year','Month','Day','Hour','Value','QC']
# 對錯誤和缺失值賦為空值
df_gz2015.loc[df_gz2015.Value<0,'Value']=np.nan
# 刪除空值記錄
df_gz2015.dropna(inplace=True)
#增加空氣質量等級欄位‘Grade’
df_gz2015.loc[:, 'Grade'] = df_gz2015['Value'].apply(get_grade)
In [17]:
df_gz2015.head()
Out[17]:
Year | Month | Day | Hour | Value | QC | Grade |
---|---|---|---|---|---|---|
0 | 2015 | 1 | 1 | 0 | 38.0 | Valid |
1 | 2015 | 1 | 1 | 1 | 40.0 | Valid |
2 | 2015 | 1 | 1 | 2 | 40.0 | Valid |
3 | 2015 | 1 | 1 | 3 | 34.0 | Valid |
4 | 2015 | 1 | 1 | 4 | 42.0 | Valid |
好了,我們已經把本次分析所需的資料集全部準備完畢,接下來就是進行資料的分析
<未完待續>