- 개요
이전 포스트에서 서울 교통량과 대기오염물질 농도 자료에 대한 전처리 작업을 수행했습니다.
이번에는 설날기간과 아닌 기간의 교통량/대기오염물질 농도를 확인하고 해석합니다.
- 분석기간 설정
설날기간은 말그대로 설날연휴 기간이지만 설날과 비교하기 위한 설날이 아닌 기간을 어떻게 정해야할까요.
저는 설날이 아닌 기간을 1월, 2월 중 설날이 아닌 기간으로 정했습니다.
설날은 항상 1월 아니면 2월이며, 1월, 2월의 교통량과 대기오염물질의 특성이 그렇게 다르지 않을 것으로 가정했습니다.
연구를 하거나 논문을 쓰시는 분들은 위의 사항을 엄밀히 확인하셔야 합니다.
전 그냥 블로그 글이니까 대충 넘어가는 겁니다.
그리고 앞으로 설날이 아닌 기간은 비설날기간으로 명명하겠습니다.
- 설날기간/비설날기간의 교통량 분류
설날기간/비설날기간의 분류 과정은 아래와 같습니다.
1. 특정연도의 1~2월 기간을 pd.DataFrame으로 추출
2. 1에서 추출한 pd.DataFrame을 설날기간과 비설날기간으로 나누어 pd.DataFrame으로 각각 저장
3. 모든 연도에 대해 1, 2를 반복
import pandas as pd
import numpy as np
df_tra = pd.read_csv('seoul_traffic.csv')
df_tra['datetime'] = pd.to_datetime(df_tra['datetime'])
# 연도별 설날 시작날짜와 끝나는 날짜를 dictionary로 저장
date_newyear = {
'2016': ['2016-02-06 00:00:00', '2016-02-10 23:00:00'],
'2017': ['2017-01-27 00:00:00', '2017-01-30 23:00:00'],
'2018': ['2018-02-15 00:00:00', '2018-02-18 23:00:00'],
'2019': ['2019-02-02 00:00:00', '2019-02-06 23:00:00'],
'2020': ['2020-01-24 00:00:00', '2020-01-27 23:00:00'],
'2021': ['2021-02-11 00:00:00', '2021-02-14 23:00:00'],
'2022': ['2022-01-29 00:00:00', '2022-02-02 23:00:00'],
'2023': ['2023-01-21 00:00:00', '2023-01-24 23:00:00'],
'2024': ['2024-02-09 00:00:00', '2024-02-12 23:00:00']
}
"""
split_new_year 설명
input
df: 추출을 원하는 pd.DataFrame
syr: 시작연도
fyr: 종료연도
output
df_new: 설날기간 추출
df_not_new: 비설날기간 추출
"""
def split_new_year(df, syr, fyr):
df_new = []
df_not_new =[]
for year in range(syr, fyr+1):
sdate = date_newyear[str(year)][0]
edate = date_newyear[str(year)][1]
# year 연도의 1, 2월을 따로 추출해서 df_로 저장
df_ = df[(df['datetime'].dt.year == year) & (df['datetime'].dt.month <= 2)].copy()
# condition은 설날기간이면 True, 아니면 False
condition = (df_['datetime'] >= sdate) & (df_['datetime'] <= edate)
df_new.append(df_[condition])
# ~condition은 True, False가 뒤바뀌며, 비설날기간이 True
df_not_new.append(df_[~condition])
df_new = pd.concat(df_new)
df_not_new = pd.concat(df_not_new)
return df_new, df_not_new
df_tra_new, df_tra_not_new = split_new_year(df_tra, 2016, 2024)
- 설날기간/비설날기간의 교통량 시각화
설날기간/비설날기간의 모든 관측지점의 교통량 합을 y축으로 시간(hour)을 x축으로 시각화합니다.
# 0시부터 23시의 각각 시간에 대한 모든 지점의 교통량 합을 yy_tra_new, yy_tra_not_new로 저장합니다
cols = [f'{i}시' for i in range(1, 23+1)]
yy_tra_new = df_tra_new[cols].sum().values
yy_tra_not_new = df_tra_not_new[cols].sum().values
# 다음은 그림 그리는 코드입니다.
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
fn_font = 'NanumGothic.ttf'
fig = plt.figure(figsize=(8, 3))
ax = fig.add_subplot()
scale = 1e-7 # 값이 10^7 정도이므로 보기좋게 한자리수로 만들기위해 scale을 곱합니다.
ax.plot(yy_tra_new * scale, marker='o', markersize=4, color='red', label='설날')
ax.plot(yy_tra_not_new * scale , marker='o', markersize=4, color='blue', label='비설날')
fontprop = fm.FontProperties(fname=fn_font, size=18)
ax.set_title('설날/비설날기간 교통량', fontproperties=fontprop)
ax.set_xticks(range(0, 24, 6));
ax.set_xticklabels(ax.get_xticks(), fontsize=12);
fontprop = fm.FontProperties(fname=fn_font, size=14)
ax.set_xlabel('시간', fontproperties=fontprop);
ax.set_xlim(-0.5, 23.5)
ax.set_yticks(range(0, 9, 2));
ax.set_yticklabels(ax.get_yticks(), fontsize=12);
ax.set_ylabel('교통량(*1e7)', fontproperties=fontprop);
ax.set_ylim(0, 8)
fontprop = fm.FontProperties(fname=fn_font, size=10)
ax.legend(prop=fontprop) # ax.legend()에 한글 폰트를 적용시킬 땐 fontproperties가 아니라 prop을 바꿔야함
먼저 설날(빨강)기간의 교통량을 보면 다들 예상했듯 모든 시간에 차가 거의 없습니다.
비설날(파랑)기간에는 새벽에 교통량이 적다가 4~5시 즈음부터 차량이 급격히 증가합니다. 아마 사람들이 이 시간에 출근하기 때문이겠죠.
여기서 재미있는 점은 출근시간이 지나도 차가 전혀 줄어들지 않습니다. 그리고 퇴근시간 이후로 서서히 교통량이 감소합니다.
위의 그림에서는 상행/하행의 교통량을 모두 합했기 때문에 출근/퇴근시간의 교통량 최댓값이 나타나지 않습니다.
참고로 보통 출근시간에 상행 교통량의 최댓값이 나타난다면 퇴근시간에 하행 교통량의 최댓값이 나오고 반대도 마찬가지입니다.
요약하자면 설날에는 차가 엄청 적을 뿐더러 시간에 따른 변화도 거의 없습니다.
- 설날/비설날기간의 대기오염물질 농도 시각화
대기오염물질 농도 자료를 처리할 때 결측치 비율을 확인하지 않고 저장을 했으므로 이러한 작업을 해줘야 합니다.
다음으로 그림을 그릴 수 있게 자료처리를 합니다.
stn_count = df_air['측정소코드'].value_counts()
stn_list_air = stn_count[stn_count == 13560].index.tolist() # 결측이 없으면 13560개
print(stn_list_air)
df_air = df_air[df_air['측정소코드'].isin(stn_list_air)]
df_air['datetime'] = pd.to_datetime(df_air['측정일시'], format='%Y%m%d%H')
df_air['hour'] = df_air['datetime'].dt.hour
df_air_new, df_air_not_new = split_new_year(df_air, 2016, 2024)
# yys와 yys_not에 그림을 그리기 위한 숫자를 저장
df_air_new_group = df_air_new.groupby(['측정소코드', 'hour'])[['NO2', 'CO', 'O3']].mean()
df_air_not_new_group = df_air_not_new.groupby(['측정소코드', 'hour'])[['NO2', 'CO', 'O3']].mean()
yys = []
yys_not = []
for stn in stn_list_air:
yys.append(df_air_new_group .loc[stn, :])
yys_not.append(df_air_not_new_group .loc[stn, :])
다음은 그림을 그리는 코드로 모든 지점에 대한 NO2, CO, O3 농도를 xy그래프로 그립니다.
6행 3열로 그림을 그릴 것이며 행은 관측지점, 열은 대기오염물질입니다.
import matplotlib.pyplot as plt
fig, axs = plt.subplots(6, 3, figsize=(10, 12))
varnames = ['CO', 'NO2', 'O3']
for i in range(6):
for j, varname in enumerate(varnames):
ax = axs[i][j]
ax.plot(yys[i][varname], marker='o', markersize=4, color='red', label='설날')
ax.plot(yys_not[i][varname], marker='o', markersize=4, color='blue', label='비설날')
fontprop = fm.FontProperties(fname=fn_font, size=18)
ax.set_xticks(range(0, 24, 6));
ax.set_xticklabels(ax.get_xticks(), fontsize=12);
ax.set_xlim(-0.5, 23.5)
fontprop = fm.FontProperties(fname=fn_font, size=18)
for j, varname in enumerate(varnames):
axs[0][j].set_title(varname, fontproperties=fontprop)
fontprop = fm.FontProperties(fname=fn_font, size=10)
axs[0][2].legend(prop=fontprop)
fontprop = fm.FontProperties(fname=fn_font, size=14)
for j in range(3):
axs[5][j].set_xlabel('시간', fontproperties=fontprop);
먼저 CO, NO2 그림을 해석해봅시다.
CO, NO2는 자동차가 배출하는 대기오염물질로 모든 지점에서 비설날기간의 농도가 더 높습니다.
비설날기간에는 출근시간에 농도가 증가하는 것이 뚜렷하지만 설날기간에는 그렇지 않습니다. 설날에 교통량이 적기 때문이겠죠.
오전 9시 이후 설날기간이든 비설날기간이든 농도가 감소합니다. 이 시간에는 햇빛이 대기의 순환을 일으켜 대기오염물질이 한 곳에 쌓이지 못하므로 농도가 낮아집니다.
다음으로 O3를 보시면 반대로 비설날기간의 O3 농도가 더 높습니다.
O3는 자동차가 배출하는 물질이 아니지만 O3 농도는 NOx(NO, NO2)와 반비례합니다.
설날기간에는 NOx가 적기 때문에 O3가 높은 것입니다. 이에 대한 자세한 설명은 일반화학이나 대기화학 교과서를 참고하세요.
- 결론
저는 처음에 설날에는 교통량이 적으니 자동차 배출가스인 CO, NO2 농도가 낮지 않을까?라는 의문에 이를 실제로 확인해봤습니다. 실제로 설날에 교통량은 적고, CO와 NO2 농도는 낮습니다.
사실 자료만 있으면 정말 확인하기 쉬운 것이지만 이 자료를 구하고 정제하는 과정이 어려우신 분들도 있을 것입니다.
물론 이 포스트에서는 엄밀한 분석을 한 것은 아느므로 이런 분석을 하여 발표하실 분들은 좀 더 신경써서 분석하시길 바랍니다.