4 minute read

전처리 Part.3에서는 격자별로 신호등이나 CCTV와 같은 교통시설물들에 대한 정보와 일별, 시간별 혼잡도 데이터를 추가했다.

전처리 Part.3(by using Python)

# 필요한 라이브러리 import

import platform
import folium
import math
from tqdm import tqdm
from shapely import wkt
from shapely.geometry import Point, Polygon, LineString

import numpy as np
import pandas as pd
import geopandas as gpd
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm

if platform.system() == 'Darwin': # 맥
        plt.rc('font', family='AppleGothic') 
elif platform.system() == 'Windows': # 윈도우
        plt.rc('font', family='Malgun Gothic') 
elif platform.system() == 'Linux': # 리눅스 (구글 Colab)
        plt.rc('font', family='Malgun Gothic')
plt.rcParams['axes.unicode_minus'] = False

import warnings
warnings.filterwarnings(action = 'ignore')
#데이터 불러오기
daejeon_signal_walk = gpd.read_file('3.대전광역시_신호등(보행등).geojson')
daejeon_signal_car = gpd.read_file('4.대전광역시_신호등(차량등).geojson')
cctv = gpd.read_file('10.대전광역시_교통CCTV.geojson')
weather = pd.read_csv('16.대전광역시_기상데이터(2017~2019).csv')
road_detail = gpd.read_file('19.대전광역시_상세도로망(2018).geojson')
day_time_accident = pd.read_csv('20.대전광역시_평일_일별_시간대별_추정교통량(2018).csv')
day_time_confuse = pd.read_csv('21.대전광역시_평일_일별_혼잡빈도강도(2018).csv')
day_time_times = pd.read_csv('22.대전광역시_평일_일별_혼잡시간강도(2018).csv')



5. accident_count_filter 데이터 불러오기(유의미한 격자만 추려낸 데이터)

도로가 지나다니는 격자인 accident_gid 데이터와 모란지수를 활용해서 유의미한 격자만 추려낸 accident_count_filter 데이터를 불러온다.

accident_gid = pd.read_csv('accident_gid.csv', index_col = 0)
print(np.shape(accident_gid))
accident_gid.head(3)

image



accident_count_filter = pd.read_csv('accident_count_filter.csv')
accident_count_filter['geometry'] = [wkt.loads(line) for line in list(accident_count_filter['geometry'])]
print(np.shape(accident_count_filter))
accident_count_filter.head(3)

image



6. 교통안전시설물 - 보행자 신호등의 geometry에 따라 그에 일치하는 gid(격자) Labeling 및 병합

get_gid함수는 within 함수를 사용해서 신호등 좌표와 격자좌표가 교차하면 그 신호등에 해당격자를 맵핑해주는 함수이다.

def get_gid(criteria, df) : # within 함수 사용
    gids = pd.DataFrame()
    gidss = []
    for i in tqdm(list(df.index)) :
        for j in list(criteria.index) : 
            if df.loc[i, 'geometry'].within(criteria.loc[j, 'geometry']) : # criteria와 df의 geometry가 교차하는지 확인
                gids = pd.concat([gids, df.loc[[i,]]])
                gidss.append(criteria.loc[j, 'gid'])
                break
    gids['gid'] = gidss
    return gids



get_gid 함수를 통해 criteriadfgeometry 값에 대하여 두 데이터가 서로 교차(within) 하는지 확인하여 그에 맞는 gidLabeling한다. 또한, 이 함수를 통해 도출된 gid와 유의미한 격자 데이터만 추려낸 gid를 사용하여 데이터를 병합했다.

## 보행자 신호등에 격자를 맵핑
signal_walk_samp = get_gid(accident_count_filter, daejeon_signal_walk)
signal_walk_samp.to_csv('final_signal_walk.csv')
final_signal_walk = pd.read_csv('final_signal_walk.csv', index_col = 0)
print(np.shape(final_signal_walk))
final_signal_walk.head()

image


신호등이 없어서 NA로 표시된 격자는 신호등 수를 0으로 대체.

signal_walk_count = final_signal_walk.groupby('gid').count()[['geometry']]
signal_walk_count.reset_index(inplace=True)
signal_walk_count.columns = ['gid', '신호등_보행자수']

accident_count_filter = accident_count_filter.merge(signal_walk_count, on = 'gid', how = 'left')
accident_count_filter['신호등_보행자수'] = accident_count_filter['신호등_보행자수'].fillna(0)
print(np.shape(accident_count_filter))
accident_count_filter.head(3)

image



7. 교통안전시설물 - 차량 신호등의 geometry에 따라 그에 일치하는 gid(격자) Labeling 및 병합

보행자 신호등과 똑같은 방법으로 진행

## 차량 신호등
signal_car_samp = get_gid(accident_count_filter, daejeon_signal_car)
signal_car_samp.to_csv('final_signal_car.csv')
final_signal_car = pd.read_csv('final_signal_car.csv', index_col = 0)
print(np.shape(final_signal_car))
final_signal_car.head()

image



signal_car_count = final_signal_car.groupby('gid').count()[['geometry']]
signal_car_count.reset_index(inplace=True)
signal_car_count.columns = ['gid', '신호등_차량등수']

accident_count_filter = accident_count_filter.merge(signal_car_count, on = 'gid', how = 'left')
accident_count_filter['신호등_차량등수'] = accident_count_filter['신호등_차량등수'].fillna(0)
print(np.shape(accident_count_filter))
accident_count_filter.head(3)

image



8. 교통안전시설물 - CCTV의 geometry에 따라 그에 일치하는 gid(격자) Labeling 및 병합

## CCTV
cctv_samp = get_gid(accident_count_filter, cctv)
cctv_samp.to_csv('final_cctv.csv')
final_cctv = pd.read_csv('final_cctv.csv', index_col = 0)
print(np.shape(final_cctv))
final_cctv.head()

image



cctv_count = final_cctv.groupby('gid').count()[['geometry']]
cctv_count.reset_index(inplace=True)
cctv_count.columns = ['gid', 'cctv수']

accident_count_filter = accident_count_filter.merge(cctv_count, on = 'gid', how = 'left')
accident_count_filter['cctv수'] = accident_count_filter['cctv수'].fillna(0)
print(np.shape(accident_count_filter))
accident_count_filter.head(3)

image



accident_count_filter.to_csv('accident_count_filter_1.csv') # 신호등(보행등), 신호등(차량등), cctv수까지 merge한 상태.



9. 교통혼잡빈도 데이터의 geometry에 따라 그에 일치하는 gid(격자) Labeling 및 병합

accident_count_filter_1 = pd.read_csv('accident_count_filter_1.csv', index_col = 0)
accident_count_filter_1['geometry'] = [wkt.loads(line) for line in list(accident_count_filter_1['geometry'])] # str 형태에서 geometry 형태로 형 변환
print(np.shape(accident_count_filter_1))
accident_count_filter_1.head(3)

image



상세도로망 데이터에 geometry 정보가 있기 때문에 혼잡빈도 데이터와 상세도로망 데이터를 LinkID를 기준으로 합친다면 get_gid2 함수를 통해 격자별로 혼잡빈도강도를 적용할 수 있게 된다.

day_time_confuse['link_id'] = [int(id/100) for id in list(day_time_confuse['상세도로망_LinkID'])] # 상세도로망_LinkID에서 link_id 추출 
road_detail = road_detail.astype({'link_id' : 'int64'})
day_time_confused = day_time_confuse.merge(road_detail, on='link_id', how='left') # 위에서 만든 link_id를 geometry가 있는 road_detail 데이터와 병합
print(np.shape(day_time_confused))
day_time_confused.head(2)

image



get_gid2 함수는 위에서 만든 get_gid와 원리는 똑같지만 도로 형태는 일반 좌표정보가 아닌 Polygon 형태이기 때문에 within이 아닌 crosses 사용했다. geometry가 서로 교차하면 해당 LinkID에 격자를 맵핑해 줄 것이다.

def get_gid2(criteria, df) :
    gids = pd.DataFrame()
    gidss = []
    for i in tqdm(list(df.index)) :
        for j in list(criteria.index) : 
            if df.loc[i, 'geometry'].crosses(criteria.loc[j, 'geometry']) : 
                gids = pd.concat([gids, df.loc[[i,]]])
                gidss.append(criteria.loc[j, 'gid'])
                break
    gids['gid'] = gidss
    return gids

get_gid2함수를 사용하여 도로링크ID별 gid를 얻어낸다.

## 교통혼잡도
accident_count_filter_2 = get_gid2(accident_count_filter_1, day_time_confused)
accident_count_filter_2.to_csv('accident_count_filter_2.csv')
accident_count_filter_2 = pd.read_csv('accident_count_filter_2.csv', index_col = 0)
accident_count_filter_2['geometry'] = [wkt.loads(line) for line in list(accident_count_filter_2['geometry'])] #str을 geometry 타입으로 변환
print(np.shape(accident_count_filter_2))
accident_count_filter_2.head(3)

image



격자별로 또, 일별로 혼잡빈도강도가 다를 것이기 때문에 한 격자라도 여러 일에 걸쳐서 혼잡빈도강도를 가지고 있을 것이다. 따라서 격자별로 이 혼잡빈도강도를 평균내서 새로운 변수를 추가하자.

confused = accident_count_filter_2.groupby('gid').mean()[['혼잡빈도강도']] # 격자별로 혼잡빈도강도의 평균 값을 사용
confused.reset_index(inplace=True)

accident_count_filter_1 = accident_count_filter_1.merge(confused, on = 'gid', how = 'left')
accident_count_filter_1['혼잡빈도강도'] = accident_count_filter_1['혼잡빈도강도'].fillna(0) #격자별 혼잡빈도강도가 없는 격자는 0으로 대체
print(np.shape(accident_count_filter_1))
accident_count_filter_1.head(3)

image



10. 교통혼잡시간 데이터의 geometry에 따라 그에 일치하는 gid(격자) Labeling 및 병합

위에서 다뤘던 교통 혼잡빈도강도 데이터와 똑같은 방식으로 교통 혼잡시간강도 데이터를 처리했다.

#링크ID 추출
day_time_times['link_id'] = [int(id/100) for id in list(day_time_confuse['상세도로망_LinkID']) ]
day_time_timed = day_time_times.merge(road_detail, on='link_id', how='left')
print(np.shape(day_time_timed))
day_time_times.head(2)

image



# 교통혼잡시간
# 혼잡시간강도 데이터에도 gid 맵핑
accident_count_filter_4 = get_gid2(accident_count_filter_3, day_time_times)
accident_count_filter_4.to_csv('accident_count_filter_4.csv')
accident_count_filter_4 = pd.read_csv('accident_count_filter_4.csv', index_col = 0)
accident_count_filter_4 = accident_count_filter_4.reset_index(drop = True)
accident_count_filter_4['geometry'] = [wkt.loads(line) for line in list(accident_count_filter_4['geometry'])]
print(np.shape(accident_count_filter_4))
accident_count_filter_4.head(3)

image



timed = accident_count_filter_4.groupby('gid').mean()[['혼잡시간강도']] # 격자별로 혼잡시간강도의 평균 값을 사용
timed.reset_index(inplace=True)

accident_count_filter_5 = accident_count_filter_3.merge(timed, on = 'gid', how = 'left')
accident_count_filter_5['혼잡시간강도'] = accident_count_filter_5['혼잡시간강도'].fillna(0)
print(np.shape(accident_count_filter_5))
accident_count_filter_5.head(3)

image



11. 시간대별 추정교통량 데이터의 geometry에 따라 그에 일치하는 gid(격자) Labeling 및 병합

accident_count_filter_2 데이터에 이미 LinkID별로 gid가 있기 때문에 굳이 get_gid2함수를 사용하지 않아도 LinkID별로 일별, 시간별, 전체 추정 교통량을 평균내어서 격자별 전체 추정 교통량 변수를 추가할 수 있다.

day_time_accident['link_id'] = [int(id/100) for id in list(day_time_accident['상세도로망_LinkID']) ]
day_time_accidentd = day_time_accident.merge(road_detail, on='link_id', how='left')
day_time_accidentd.groupby('link_id').mean('전체_추정교통량')
day_time_accidentd.reset_index(inplace=True)
day_time_accidentd = day_time_accidentd.merge(accident_count_filter_2[['gid', 'link_id']], on='link_id', how='left')
day_time_sample = day_time_accidentd.loc[:, ['전체_추정교통량', 'gid']]
day_time_sample = day_time_sample.groupby('gid').mean()
day_time_sample.reset_index(inplace = True)
accident_count_filter_5 = accident_count_filter_5.merge(day_time_sample, on = 'gid', how = 'left')
accident_count_filter_5 = accident_count_filter_5.fillna(0)
print(np.shape(accident_count_filter_5))
accident_count_filter_5.head(5)

image



accident_count_filter_5.to_csv('accident_count_filter_5.csv') # 신호등(보행등), 신호등(차량등), cctv수, 혼잡빈도, 혼잡시간, 교통추정량까지 merge한 상태.

Weather 변수를 연도별로 나눠주기

weather_2017 = weather[weather['일시'] < '2018-01-01']
weather_2018 = weather[(weather['일시'] >= '2018-01-01') & (weather['일시'] <= '2018-12-31')].reset_index(drop = True)
weather_2019 = weather[weather['일시'] >= '2019-01-01'].reset_index(drop = True)
weather_2017.to_csv('weather_2017.csv')
weather_2018.to_csv('weather_2018.csv')
weather_2019.to_csv('weather_2019.csv')

Categories:

Updated: