서울시 내 이륜차 안전문제해결을 위한 취약지점 분석
import pandas as pd
import numpy as np
import matplotlib .pyplot as plt
plt .rc ('font' , family = "Malgun Gothic" )
file = pd .read_csv ("./서울시 교통사고 현황(구별) 통계 (2016 ~ 2020).txt" , sep = "\t " , index_col = 0 , encoding = "UTF-8" ,
names = ["지역" , "발생건수" , "자동차 1만대당 발생건수" , "사망자수" , "인구 10만명당 사망자수" , "부상자수" , "인구 10만명당 부상자수" ])
file .drop (columns = ["부상자수" , "인구 10만명당 부상자수" , "자동차 1만대당 발생건수" , "인구 10만명당 사망자수" ], inplace = True )
file = file [file .지역 == "합계" ]
file ["발생건수" ] = file ["발생건수" ].str .replace ("," , "" )
file2 = pd .read_excel ("./서울시 이륜차 교통사고 현황.xls" )
file2 .set_index ("연도" , inplace = True )
file2 .drop (columns = ["부상자수" ], inplace = True )
fig , axes = plt .subplots (1 , 2 , figsize = (23 , 8 ), constrained_layout = True )
ax1 , ax2 = axes [0 ], axes [0 ].twinx ()
file .iloc [:, 1 ].astype (np .int32 ).plot (ax = ax1 , linewidth = 3 , color = "blue" )
ax1 .legend (["전체 사고건수" ], loc = "upper left" )
ax1 .set_ylabel ("사고건수" , rotation = 0 , labelpad = 40 , fontdict = {"fontsize" : 15 })
ax1 .set_xticks (range (2016 , 2021 ))
file2 .iloc [:, 0 ].astype (np .int32 ).plot (ax = ax2 , linewidth = 3 , color = "orange" )
ax2 .legend (["이륜차 사고건수" ], loc = "upper right" )
ax3 , ax4 = axes [1 ], axes [1 ].twinx ()
file .iloc [:, 2 ].astype (np .int32 ).plot (ax = ax3 , linewidth = 3 , color = "blue" )
ax3 .legend (["전체 사고 사망자" ], loc = "upper left" )
ax3 .set_ylabel ("사망자수" , rotation = 0 , labelpad = 30 , fontdict = {"fontsize" : 15 })
axes [0 ].set_title ("서울시 연도별 교통사고 건수" , fontdict = {"fontsize" : 20 })
ax3 .set_xticks (range (2016 , 2021 ))
file2 .iloc [:, 1 ].astype (np .int32 ).plot (ax = ax4 , linewidth = 3 , color = "orange" )
ax4 .legend (["이륜차 사고 사망자" ], loc = "upper right" )
axes [1 ].set_title ("서울시 연도별 교통사고 사망자" , fontdict = {"fontsize" : 20 })
plt .show ()
서울시의 전체 교통사고와 이륜차에만 해당하는 2016 ~ 2020까지 5개년 데이터
전체 교통사고는 40000건에서 35000건 정도까지 감소추세를 보임
이에 비해 이륜차 사고로 특정하면 약 5500건에서 8500건 이상까지 가파르게 증가하는 모습을 보임
사망자 또한 사고 전체를 보면 감소하는 추세지만 이륜차 사고로 특정하면 변동이 거의 없음
plt .rc ("font" , family = "Malgun Gothic" )
df = pd .read_excel ("./서울시 동별 이륜차 사고건수 (2017~2019).xlsx" )
df .fillna (0 , inplace = True )
df ["도로형태" ].value_counts ().plot .bar (rot = 15 )
plt .title ("이륜차 사고 도로형태" , fontdict = {"fontsize" : 20 })
plt .show ()
단일로 - 기타나 교차로(일반도로) 에서 대다수의 사고가 발생
지하차도, 교량, 터널, 고가도로, 주차장 등(나머지도로) 에서는 거의 사고가 발생하지 않음
도로개수를 count 할 때 일반도로에 비해 나머지도로는 적은 영향을 미쳐야한다고 판단
df = pd .read_excel (",/서울시 동별 이륜차 사고건수 (2017~2019).xlsx" )
df .fillna (0 , inplace = True )
data = df ["도로형태" ].value_counts ().values
x = ["일반도로\n (교차로, 단일로)" , "나머지도로\n (터널, 대교, 지하차도, \n 고가도로, 주차장)" ]
fig , axes = plt .subplots (1 , 2 , figsize = (25 , 13 ))
# 일반도로의 중앙값과 나머지 도로
y = [np .median (data [:5 ]), np .sum (data [5 :])]
df = pd .DataFrame (y , index = x , columns = ["사고비율" ])
df = df / (np .median (data [:5 ]) + np .sum (data [5 :]))
df .plot .pie (rot = 0 , fontsize = 15 , subplots = True , autopct = '%1.0f%%' , ax = axes [0 ])
axes [0 ].set_title ("도로형태별 사고 비율 (일반도로 median)" , fontdict = {"fontsize" : 17 })
# 일반도로의 평균값과 나머지 도로
y = [np .mean (data [:5 ]), np .sum (data [5 :])]
df = pd .DataFrame (y , index = x , columns = ["사고비율" ])
df = df / (np .mean (data [:5 ]) + np .sum (data [5 :]))
df .plot .pie (rot = 0 , fontsize = 15 , subplots = True , autopct = '%1.0f%%' , ax = axes [1 ])
axes [1 ].set_title ("도로형태별 사고 비율 (일반도로 mean)" , fontdict = {"fontsize" : 17 })
plt .show ()
일반적으로 일반도로에서 발생하는 사고건수에 비해 나머지도로들에서 발생하는 사고건수의 비율
8 ~ 10배 정도의 차이가 발생
나머지 도로는 개수 count시 0.1로 계산
df = pd .read_excel ("./서울시 동별 이륜차 사고건수 (2017~2019).xlsx" )
df .fillna (0 , inplace = True )
df ["사고일시" ] = df ["사고일시" ].apply (lambda x : x .split (" " )[3 ])
p_df = df ["사고일시" ].value_counts () / df .shape [0 ] * 100
q1 = p_df [p_df .cumsum () > 25 ].index [0 ]
q2 = p_df [p_df .cumsum () > 50 ].index [0 ]
q3 = p_df [p_df .cumsum () > 75 ].index [0 ]
q1_index = p_df .index .tolist ().index (q1 )
q2_index = p_df .index .tolist ().index (q2 )
q3_index = p_df .index .tolist ().index (q3 )
plt .plot (range (q1_index , 24 ), [p_df [p_df .index == q1 ]] * (24 - q1_index ), "r--" )
plt .text (14 , p_df [p_df .index == q1 ], "누적 25%" , fontdict = {"fontsize" : 15 , "fontfamily" : "Malgun Gothic" })
plt .plot (range (q2_index , 24 ), [p_df [p_df .index == q2 ]] * (24 - q2_index ), "r--" )
plt .text (14 , p_df [p_df .index == q2 ], "누적 50%" , fontdict = {"fontsize" : 15 , "fontfamily" : "Malgun Gothic" })
plt .plot (range (q3_index , 24 ), [p_df [p_df .index == q3 ]] * (24 - q3_index ), "r--" )
plt .text (14 , p_df [p_df .index == q3 ], "누적 75%" , fontdict = {"fontsize" : 15 , "fontfamily" : "Malgun Gothic" })
p_df .plot .bar (rot = 45 )
plt .ylabel ("(%)" , labelpad = 15 , rotation = 0 , fontdict = {"fontsize" : 17 })
plt .xlabel ("(시간)" , fontdict = {"fontsize" : 17 })
plt .title ("시간대별 이륜차 사고 비율" , fontdict = {"fontsize" : 20 })
plt .show ()
18 ~ 20시 저녁시간대에 가장 많은 사고가 일어남
11 ~ 24시까지 이륜차 사고 전체의 75%가 발생
import pandas as pd
import matplotlib .pyplot as plt
def avg_speed (path ):
global col
for idx , file in enumerate (os .listdir (path )):
df = pd .read_excel (os .path .join (path , file ), sheet_name = 1 )
match = df ["지점명" ].apply (
lambda x : re .search (
r"이륜차가 지나가지 못하는 지점들의 명칭" ,
str (x )))
filtered = match .apply (lambda x : x is None )
df = df .loc [filtered , :]
if idx == 0 :
col = df .columns [6 :]
all_df .append (df )
result = pd .concat (all_df , axis = 0 )
re_df = result .pivot_table (col , index = ["지점번호" , "방향" ], aggfunc = "mean" )
re_df = re_df .loc [:, col ]
re_df = re_df .reset_index ("방향" )
sum_df = re_df [re_df ["방향" ] == "유입" ] + re_df [re_df ["방향" ] == "유출" ]
sum_df = sum_df .loc [:, col ]
fig , axes = plt .subplots (1 , 2 , figsize = (32 , 14 ))
# 비율로 변환
mean_df = sum_df .mean (axis = 0 ) / sum_df .mean (axis = 0 ).sum ()
mean_df *= 100
mean_df .plot .bar (ax = axes [0 ], rot = 45 , fontsize = 15 )
axes [0 ].plot (range (24 ), [100 / 24 ] * 24 , "r--" )
axes [0 ].set_title ("모든 구간의 시간별 평균" , fontdict = {"fontsize" : 15 })
axes [0 ].set_ylabel ("(%)" , labelpad = 13 , rotation = 0 , fontdict = {"fontsize" : 13 })
axes [0 ].set_xlabel ("(시간)" , fontdict = {"fontsize" : 13 })
# 비율로 변환
median_df = sum_df .median (axis = 0 ) / sum_df .median (axis = 0 ).sum ()
median_df *= 100
median_df .plot .bar (ax = axes [1 ], rot = 45 , fontsize = 15 )
axes [1 ].set_title ("모든 구간의 시간별 중앙값" , fontdict = {"fontsize" : 15 })
axes [1 ].plot (range (24 ), [100 / 24 ] * 24 , "r--" )
axes [1 ].set_ylabel ("(%)" , labelpad = 13 , rotation = 0 , fontdict = {"fontsize" : 13 })
axes [1 ].set_xlabel ("(시간)" , fontdict = {"fontsize" : 13 })
plt .show ()
2020.07 ~ 2021.06까지 1년치의 데이터를 바탕으로 함
서울시의 교통량 조사지점 중 이륜차가 지나지 못하는 지점을 제외한 나머지 지점들의 교통량에 대한 시간대별 평균, 중앙값
두 경우 모두 07 ~ 21시에 평균치를 상회했고 06시와 22시도 평균치에 근접한 비율로 교통량이 발생했음
통행량은 일부 지점에만 존재
서울 연구원에서 진행한 교통량과 통행속도간의 연구를 바탕으로 서울시 전역에 대한 데이터가 존재하는 통행속도 데이터를 대체 통행량으로 사용
중간중간 결측치가 존재하는 부분들은 제하고 평균치를 산정
2020.07 ~ 2021.06까지 1년치의 데이터를 바탕으로 함
dir = "./서울시 차량 통행 속도"
def avg (path ):
global df , sub_df
for idx , file in enumerate (os .listdir (path )):
df = pd .read_excel (os .path .join (path , file ))
df = df [df .기능유형구분 != "도시고속도로" ]
sel_df = df .pivot_table (df .columns [8 :].tolist () + ["차선수" ], index = "링크아이디" , aggfunc = "mean" )
if idx == 0 :
sum_df = sel_df
else :
sum_df += sel_df
avg_df = sum_df / 12
avg_df ["평균" ] = avg_df .mean (axis = 1 ).values
avg_df .to_csv ("서울시 통행속도(new).csv" , encoding = "CP949" )
이륜차의 통행이 불가능한 도시고속도로를 제외
나머지 도로에 대한 시간대별 평균치와 지정된 시간에 대한 평균치를 추출
나머지 변수들은 Q-GIS를 이용해 연산 or count 진행하여 최종적인 dataset (5369 x 25) 구성
import matplotlib .pyplot as plt
import pandas as pd
plt .figure (figsize = (13 , 13 ))
sns .heatmap (df .corr (), annot = True , square = True , fmt = '.2f' , cmap = plt .cm .Blues )
plt .xticks (rotation = 45 )
plt .show ()
버스정류장, 교통안전시설물, 상권과 인구 등은 서로 간에 밀접한 관계가 있기 때문에 0.5 ~ 0.8의 강한 양의 상관관계가 나타난 것으로 보임
도로 중에서도 일반도로의 75% 정도를 1, 2, 3차선이 차지하기 때문에 0.5 ~ 0.7의 강한 양의 상관관계가 나타난 것으로 보임
또한 평균통행속도는 느릴수록 교통량이 많다는 가정에 따라 도로가 없는 곳은 통행속도를 10000이라는 매우 큰 값을 주었기에 일반도로와 -0.6 정도의 강한 음의 상관관계가 나타난 것으로 보임
import matplotlib .pyplot as plt
import pandas as pd
from statsmodels .stats .outliers_influence import variance_inflation_factor
def check_vif (dataset ):
vif = pd .DataFrame ()
vif ["VIF Factor" ] = [variance_inflation_factor (dataset , i ) for i in range (dataset .shape [1 ])]
vif ["features" ] = dataset .columns
vif .index = vif ["features" ]
vif .plot .bar (rot = 25 , fontsize = 17 )
plt .title ("다중공선성 (Random forest input features)" , fontdict = {"fontsize" : 17 })
plt .show ()
결과 값이 도출되지 않은 변수들은 INF값을 가지는 경우
import matplotlib .pyplot as plt
import pandas as pd
from sklearn .model_selection import KFold
from sklearn .metrics import mean_squared_error
forest_r2 = []
forest_mse = []
svr_r2 = []
svr_mse = []
linear_r2 = []
linear_mse = []
# scaled_data - Standard Scaler로 스케일링 된 dataset
# target - ARI (종속변수)
for train_idx , val_idx in kf .split (scaled_data , target ):
train_x , train_y = scaled_data [train_idx ], target .iloc [train_idx ]
val_x , val_y = scaled_data [val_idx ], target .iloc [val_idx ]
forest .fit (train_x , train_y )
svr .fit (train_x , train_y )
linear .fit (train_x , train_y )
# random forest regressor score
f_r2 = forest .score (val_x , val_y )
f_Adj_r2 = 1 - ((1 - f_r2 ) * (len (val_y ) - 1 ) / (len (val_y ) - val_x .shape [1 ] - 1 ))
forest_r2 .append ([f_r2 , f_Adj_r2 ])
f_mse = mean_squared_error (val_y , forest .predict (val_x ))
forest_mse .append (f_mse )
# svr score
s_r2 = svr .score (val_x , val_y )
s_Adj_r2 = 1 - ((1 - s_r2 ) * (len (val_y ) - 1 ) / (len (val_y ) - val_x .shape [1 ] - 1 ))
svr_r2 .append ([s_r2 , s_Adj_r2 ])
s_mse = mean_squared_error (val_y , svr .predict (val_x ))
svr_mse .append (s_mse )
# linear regressor score
l_r2 = linear .score (val_x , val_y )
l_Adj_r2 = 1 - ((1 - l_r2 ) * (len (val_y ) - 1 ) / (len (val_y ) - val_x .shape [1 ] - 1 ))
linear_r2 .append ([l_r2 , l_Adj_r2 ])
l_mse = mean_squared_error (val_y , linear .predict (val_x ))
linear_mse .append (l_mse )
def show_annotation (fig ):
for bar in fig .patches :
fig .annotate (round (bar .get_height (), 3 ),
(bar .get_x () + bar .get_width () / 2 ,
bar .get_height ()), ha = 'center' , va = 'center' ,
size = 12 , xytext = (- 1 , 8 ),
textcoords = 'offset points' )
# R2 결과 시각화
fig , axes = plt .subplots (1 , 3 , figsize = (22 , 13 ), constrained_layout = True )
forest_r2 .append ([np .array (forest_r2 )[:, 0 ].mean (), np .array (forest_r2 )[:, 1 ].mean ()])
f_df = pd .DataFrame (forest_r2 , columns = ["Random Forest R2" , "Random Forest Adjusted_R2" ],
index = ["fold 1" , "fold 2" , "fold 3" , "Avg" ])
f_df .plot .bar (title = "Random Forest" , ax = axes [0 ], rot = 0 )
axes [0 ].set_yticks (np .arange (0 , 0.8 , 0.1 ))
svr_r2 .append ([np .array (svr_r2 )[:, 0 ].mean (), np .array (svr_r2 )[:, 1 ].mean ()])
s_df = pd .DataFrame (svr_r2 , columns = ["SVR R2" , "SVR Adjusted_R2" ], index = ["fold 1" , "fold 2" , "fold 3" , "Avg" ])
s_df .plot .bar (title = "Support Vector Machine (RBF Kernel))" , ax = axes [1 ], rot = 0 )
axes [1 ].set_yticks (np .arange (0 , 0.8 , 0.1 ))
linear_r2 .append ([np .array (linear_r2 )[:, 0 ].mean (), np .array (linear_r2 )[:, 1 ].mean ()])
l_df = pd .DataFrame (linear_r2 , columns = ["linear R2" , "linear Adjusted_R2" ], index = ["fold 1" , "fold 2" , "fold 3" , "Avg" ])
l_df .plot .bar (title = "Linear Regression" , ax = axes [2 ], rot = 0 )
axes [2 ].set_yticks (np .arange (0 , 0.8 , 0.1 ))
for ax in axes .flatten ():
show_annotation (ax )
fig .suptitle ("3-Fold Cross Validation (R2)" , fontsize = 15 )
plt .show ()
# MSE 결과 시각화
fig , axes = plt .subplots (1 , 3 , figsize = (22 , 13 ), constrained_layout = True )
forest_mse .append (np .mean (forest_mse ))
f_mse_df = pd .DataFrame (forest_mse , columns = ["Mean squared error" ],
index = ["fold 1" , "fold 2" , "fold 3" , "Avg" ])
f_mse_df .plot .bar (title = "Random Forest" , ax = axes [0 ], rot = 0 )
axes [0 ].set_yticks (np .arange (0 , 0.9 , 0.1 ))
svr_mse .append (np .mean (svr_mse ))
s_mse_df = pd .DataFrame (svr_mse , columns = ["Mean squared error" ],
index = ["fold 1" , "fold 2" , "fold 3" , "Avg" ])
s_mse_df .plot .bar (title = "Support Vector Machine (RBF kernel)" , ax = axes [1 ], rot = 0 )
axes [1 ].set_yticks (np .arange (0 , 0.9 , 0.1 ))
linear_mse .append (np .mean (linear_mse ))
l_mse_df = pd .DataFrame (linear_mse , columns = ["Mean squared error" ],
index = ["fold 1" , "fold 2" , "fold 3" , "Avg" ])
l_mse_df .plot .bar (title = "Linear Regression" , ax = axes [2 ], rot = 0 )
axes [2 ].set_yticks (np .arange (0 , 0.9 , 0.1 ))
for ax in axes .flatten ():
show_annotation (ax )
fig .suptitle ("3-Fold Cross Validation (MSE)" , fontsize = 15 )
plt .show ()
Linear regression, Random forest regressor, SVR (rbf kernel) 세 가지 모델을 사용
R-squared, Adjusted R-squared, Mean Squared Error (MSE) 세 가지 성능 평가 지표에 대해 교차 검증
feature selection (Linear regression)
df <- read.csv(" ./final_dataset.csv" , fileEncoding = " CP949" )
target <- df [, " ARI" ]
df <- df [, - c(1 , 22 )]
# standard scaling
df = data.frame (scale(df ))
model <- lm(target ~ . , data = df )
summary(model )
new_model <- step(model , direction = " both" )
summary(new_model )
단계적 선택법으로 적절한 변수 선택
유의성 검증 결과 p-value가 높았던 변수들 제거
어린이보호, 정류장, 신호등, 평균통행속도, 6차선, 7차선 , 등록이륜차, 일반도로, 경찰서
feature selection (Random forest)
import matplotlib .pyplot as plt
import pandas as pd
from sklearn .ensemble import RandomForestRegressor
forest = RandomForestRegressor (n_estimators = 500 , random_state = 42 )
forest .fit (scaled_data , target )
plt .figure (figsize = (20 , 12 ))
plt .bar (range (scaled_data .shape [1 ]), forest .feature_importances_ )
for x , fi in zip (range (scaled_data .shape [1 ]), forest .feature_importances_ ):
plt .annotate (np .round (fi , 3 ),
(x , fi ),
ha = 'center' , va = 'center' ,
size = 15 , xytext = (- 1 , 8 ),
textcoords = 'offset points' )
plt .xticks (range (scaled_data .shape [1 ]), df .columns , rotation = 30 , fontsize = 15 )
plt .title ("Feature importance" , fontdict = {"fontsize" : 17 })
plt .show ()
# Permutation importance
result = PermutationImportance (svr , scoring = "r2" , random_state = 42 ).fit (scaled_data , target )
print (eli5 .format_as_text (eli5 .explain_weights (result , top = 30 , feature_names = df .columns .tolist ())))
중요도 하위 10개의 변수 제거
무인단속카메라, 4차선, 어린이보호구역, 나머지도로, 5차선, 장애인보호구역, 경찰서, 도로없음, 6차선, 7차선
t_sne = TSNE (random_state = 42 )
df = t_sne .fit_transform (df )
plt .figure (figsize = (17 , 12 ))
plt .rc ('font' , size = 24 )
ax1 , ax2 = plt .gca (), plt .gca ().twinx ()
endpoint = 0
for k in range (2 , 6 ):
kmeans = KMeans (init = "k-means++" , random_state = 42 , n_clusters = k )
kmeans .fit (df )
label = kmeans .labels_
inertias .append (kmeans .inertia_ )
silhouettes .append (silhouette_score (df , label ))
line1 = ax1 .plot (range (2 , 6 ), inertias , "o-" , color = "b" , linewidth = 4.0 , label = "Inertia" )
ax1 .set_xlabel ("K" , labelpad = 10 , fontdict = {"fontsize" : 25 })
ax1 .set_ylabel ("Inertia" , labelpad = 10 , fontdict = {"fontsize" : 25 })
line2 = ax2 .plot (range (2 , 6 ), silhouettes , "o-" , color = "r" , linewidth = 4.0 , label = "Silhouette_score" )
ax2 .set_ylabel ("Silhouette_score" , labelpad = 10 , fontdict = {"fontsize" : 25 })
ax1 .legend (line1 + line2 , [x .get_label () for x in (line1 + line2 )], fontsize = 20 )
ax2 .annotate ('Elbow' ,
xy = (5 , silhouettes [3 ]),
xytext = (0.8 , 0.4 ),
textcoords = 'figure fraction' ,
fontsize = 20 ,
arrowprops = dict (facecolor = 'black' , shrink = 0.1 , width = 3 )
)
plt .title ("Select optimal K (K-means++)" , fontdict = {"fontsize" : 30 })
plt .savefig ("k-means++ K.png" )
T-SNE를 통해 고차원의 데이터셋을 2차원 데이터로 축소
효율적인 시각화를 위해서는 5개 이하의 군집으로 설정하는 것이 좋다고 판단
K-means++가 Gaussian Mixture에 비해 전반적인 silhouette score가 높음
K-means++의 inertia가 비교적 원만하게 꺾이기 시작하고 (elbow 지점) GaussianMixture의 silhouette score가 0.4 정도로 비교적 높은 k(5)로 군집화
t_sne = TSNE (random_state = 42 )
decomp_data = t_sne .fit_transform (df )
kmeans5 = KMeans (init = "k-means++" , random_state = 42 , n_clusters = 5 )
kmeans5 .fit (decomp_data )
K_label_5 = kmeans5 .labels_
GM = GaussianMixture (n_components = 5 , n_init = 10 , random_state = 42 )
GM .fit (decomp_data )
G_label_5 = GM .predict (decomp_data )
fig , axes = plt .subplots (1 , 2 , figsize = (23 , 10 ))
axes [0 ].scatter (decomp_data [:, 0 ], decomp_data [:, 1 ], c = K_label_5 )
axes [0 ].set_title ("K-means++ (5 cluster)" , fontdict = {"fontsize" : 30 })
axes [0 ].set_xticks ([])
axes [0 ].set_yticks ([])
axes [1 ].scatter (decomp_data [:, 0 ], decomp_data [:, 1 ], c = G_label_5 )
axes [1 ].set_title ("Gaussian Mixture (5 cluster)" , fontdict = {"fontsize" : 30 })
axes [1 ].set_xticks ([])
axes [1 ].set_yticks ([])
plt .show ()
t_sne = TSNE (n_components = 3 , random_state = 42 )
decomp_data = t_sne .fit_transform (df )
kmeans5 = KMeans (init = "k-means++" , random_state = 42 , n_clusters = 5 )
kmeans5 .fit (decomp_data )
K_label_5 = kmeans5 .labels_
GM = GaussianMixture (n_components = 5 , n_init = 10 , random_state = 42 )
GM .fit (decomp_data )
G_label_5 = GM .predict (decomp_data )
fig , axes = plt .subplots (1 , 2 , figsize = (23 , 10 ), subplot_kw = {"projection" : "3d" })
axes [0 ].scatter (decomp_data [:, 0 ], decomp_data [:, 1 ], decomp_data [:, 2 ], c = K_label_5 )
axes [0 ].set_title ("K-means++ (5 cluster)" , fontdict = {"fontsize" : 30 })
axes [0 ].set_xticks ([])
axes [0 ].set_yticks ([])
axes [1 ].scatter (decomp_data [:, 0 ], decomp_data [:, 1 ], decomp_data [:, 2 ], c = G_label_5 )
axes [1 ].set_title ("Gaussian Mixture (5 cluster)" , fontdict = {"fontsize" : 30 })
axes [1 ].set_xticks ([])
axes [1 ].set_yticks ([])
plt .show ()
t_sne = TSNE (n_components = 2 , random_state = 42 )
decomp_data = t_sne .fit_transform (df )
kmeans5 = KMeans (init = "k-means++" , random_state = 42 , n_clusters = 5 )
kmeans5 .fit (decomp_data )
K_label_5 = kmeans5 .labels_
# Standard Scaling 역변환
inverse_df = scaler .inverse_transform (df )
inverse_df = pd .DataFrame (inverse_df , columns = df .columns )
# Min Max Scaling 적용
min_max = MinMaxScaler ()
m_scaled = min_max .fit_transform (inverse_df )
m_scaled_df = pd .DataFrame (m_scaled , columns = df .columns )
m_scaled_df ["cluster" ] = K_label_5
m_scaled_df .pivot_table (df .columns [:- 1 ], index = "cluster" , aggfunc = "mean" ).plot .bar (width = 0.7 , cmap = plt .cm .tab10 , rot = 0 , fontsize = 17 )
plt .xlabel ("Cluster" , fontdict = {"fontsize" : 17 })
plt .title ("Cluster별 평균치 (MinMaxScaled)" , fontdict = {"fontsize" : 20 })
plt .show ()
2와 3은 매우 높은 통행속도를 보이는데, 앞서 통행량을 구하기 위해 통행속도를 이용했으므로 통행속도가 매우 높다는 것은 교통량이 없음을 의미.
4의 경우 통행속도가 매우 낮게 나오고, 다른 변수들은 평균적으로 높게 나타났습니다. 교통량도 많고, 인구도 많고, 다양한 시설이 있는 도심지역의 특성을 나타냄
0과 1은 상대적으로 2와 3보다는 높지만 4에 비해서는 낮은 인구, 교통안전시설물, 교통량이 나타남