문제 정의

초등학교 근처는 교통사고를 예방책이 잘 준비되어 있을까? ### Target Audiance 초등학교 학부모, 학생들
### 필요한 데이터 분석 - 초등학교 위치 정보 - 초등학생 교통사고 유형 정보 - 초등학교 근처 교통 특징 정보 - 위험 요소 : 횡단보도, 공사장, ?? - 안전 요소 : 과속방지 CCTV, 과속 방지턱, 엘로우카펫 교통사고 예방방법 종류 ### 가설 설정 교통사고 예방방법이 많이 적용된 초등학교는 안전하다. 초등학생에게 자주 발생하는 교통사고를 분석하면 초등학교에 필요한 예방방법을 예측할 수 있다. 초등학교 근처의 교통 특징을 보면 교통사고 위험도를 알 수 있다 ### 데이터 - 횡단보도 : 서울특별시_교통안전시설물 횡단보도 정보 - 학교위치 및 기본정보 : 학교위치 및 기본정보 - 교통사고 다발 어린이보호구역 : ???

import pandas as pd
import numpy as np
import folium
import pyproj
!pip install xlrd
import xlrd
Requirement already satisfied: xlrd in /root/00_PRJ/blog_group/quarto/gabrielwithappy.github.io/.venv/lib/python3.8/site-packages (2.0.1)
df_summary_grade = pd.read_excel('./학년별_스쿨존내_어린이(12세이하)_보행_사상자_2023.xls')
df_summary_grade= df_summary_grade.rename(columns={'기준년도':'사고유형'})
df_summary_grade = df_summary_grade.melt('사고유형', value_vars=['1학년', '2학년', '3학년', '4학년', '5학년', '6학년'])
df_summary_grade= df_summary_grade.rename(columns={'variable':'학년'})
df_summary_grade_sum = df_summary_grade.groupby('학년')['value'].sum().to_frame()
df_summary_grade_sum= df_summary_grade_sum.reset_index()

import plotly.graph_objects as go
import plotly.express as px
fig = px.bar(df_summary_grade_sum, x='학년', y='value', title='상권분석 그래프', orientation='v')#, template='seaborn')
fig.show()
df_summary_behavior = pd.read_excel('./행동유형별_스쿨존내_어린이(12세이하)_보행_사상자.xls', header=1)
df_summary_behavior = df_summary_behavior.dropna()
_loop = df_summary_behavior.columns
_loop = _loop.drop(['합계'])
_loop
df_summary_behavior = df_summary_behavior.melt(id_vars = '기준년도', value_vars=_loop)
df_summary_behavior
df_summary_behavior= df_summary_behavior.rename(columns={'variable':'행동유형'})
df_summary_behavior = df_summary_behavior.reset_index()
df_summary_behavior
df_summary_behavior_sum = df_summary_behavior.groupby('행동유형')['value'].sum().to_frame()
df_summary_behavior_sum= df_summary_behavior_sum.reset_index()
df_summary_behavior_sum

fig = px.bar(df_summary_behavior_sum, x='행동유형', y='value', title='상권분석 그래프', orientation='v')#, template='seaborn')
fig.show()
df_raw = pd.read_csv('./seoul_cross_all.csv', encoding='cp949')
# display(df_raw.head())


/tmp/ipykernel_4713/3039976074.py:1: DtypeWarning:

Columns (17,18,19,24,25) have mixed types. Specify dtype option on import or set low_memory=False.

데이터 타입 확인

df_raw.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 121553 entries, 0 to 121552
Data columns (total 28 columns):
 #   Column       Non-Null Count   Dtype  
---  ------       --------------   -----  
 0   횡단보도관리번호     121553 non-null  object 
 1   상태 (공통)      121545 non-null  float64
 2   횡단보도종류코드     121544 non-null  float64
 3   가로길이         90355 non-null   float64
 4   세로길이         90355 non-null   float64
 5   화살표시수량       110303 non-null  float64
 6   화살표시길이       102943 non-null  float64
 7   고가 (공통)      121544 non-null  float64
 8   구경찰서코드 (공통)  121366 non-null  float64
 9   구코드 (공통)     120826 non-null  float64
 10  동코드 (공통)     121251 non-null  float64
 11  지번           119588 non-null  object 
 12  신경찰서코드 (공통)  121516 non-null  float64
 13  작업구분 (공통)    121553 non-null  int64  
 14  표출구분 (공통)    121553 non-null  int64  
 15  도로구분 (공통)    120606 non-null  float64
 16  관할사업소 (공통)   120704 non-null  float64
 17  신규정규화ID      38800 non-null   object 
 18  설치일          18101 non-null   object 
 19  교체일          18196 non-null   object 
 20  공간데이터        0 non-null       float64
 21  이력ID         121553 non-null  int64  
 22  공사관리번호       115919 non-null  object 
 23  구횡단보도관리번호    120897 non-null  object 
 24  공사형태 (공통)    108876 non-null  object 
 25  교차로코드        21820 non-null   object 
 26  X좌표          121538 non-null  float64
 27  Y좌표          121538 non-null  float64
dtypes: float64(16), int64(3), object(9)
memory usage: 26.0+ MB

결측치 검사

df_raw[df_raw['구코드 (공통)'] == 530].isnull().sum()
횡단보도관리번호          0
상태 (공통)           0
횡단보도종류코드          0
가로길이           1598
세로길이           1598
화살표시수량          716
화살표시길이          963
고가 (공통)           0
구경찰서코드 (공통)      19
구코드 (공통)          0
동코드 (공통)          0
지번               65
신경찰서코드 (공통)       0
작업구분 (공통)         0
표출구분 (공통)         0
도로구분 (공통)        22
관할사업소 (공통)       20
신규정규화ID        3348
설치일            4127
교체일            4128
공간데이터          5216
이력ID              0
공사관리번호          144
구횡단보도관리번호       228
공사형태 (공통)       580
교차로코드          4283
X좌표               1
Y좌표               1
dtype: int64
df=df_raw.dropna(subset=['X좌표','Y좌표'])
df.isnull().sum()
display(df.head(2))
display(df.columns)
횡단보도관리번호 상태 (공통) 횡단보도종류코드 가로길이 세로길이 화살표시수량 화살표시길이 고가 (공통) 구경찰서코드 (공통) 구코드 (공통) ... 설치일 교체일 공간데이터 이력ID 공사관리번호 구횡단보도관리번호 공사형태 (공통) 교차로코드 X좌표 Y좌표
0 06-0000030030 1.0 2.0 0.0 0.0 4.0 1.0 1.0 390.0 380.0 ... NaN NaN NaN 101702 2008-1108-025 06-030030 1 NaN 192679.8948 559453.6699
2 06-0000030054 1.0 2.0 0.0 0.0 0.0 1.0 1.0 390.0 380.0 ... NaN NaN NaN 37033 2000-0000-000 06-030054 NaN NaN 194094.3509 559522.4508

2 rows × 28 columns

Index(['횡단보도관리번호', '상태 (공통)', '횡단보도종류코드', '가로길이', '세로길이', '화살표시수량', '화살표시길이',
       '고가 (공통)', '구경찰서코드 (공통)', '구코드 (공통)', '동코드 (공통)', '지번', '신경찰서코드 (공통)',
       '작업구분 (공통)', '표출구분 (공통)', '도로구분 (공통)', '관할사업소 (공통)', '신규정규화ID', '설치일',
       '교체일', '공간데이터', '이력ID', '공사관리번호', '구횡단보도관리번호', '공사형태 (공통)', '교차로코드',
       'X좌표', 'Y좌표'],
      dtype='object')
df.describe()
상태 (공통) 횡단보도종류코드 가로길이 세로길이 화살표시수량 화살표시길이 고가 (공통) 구경찰서코드 (공통) 구코드 (공통) 동코드 (공통) 신경찰서코드 (공통) 작업구분 (공통) 표출구분 (공통) 도로구분 (공통) 관할사업소 (공통) 공간데이터 이력ID X좌표 Y좌표
count 121530.000000 121529.000000 90340.000000 90340.000000 110288.000000 102928.000000 121529.000000 121351.000000 120811.000000 121236.000000 121501.000000 121538.000000 121538.000000 120591.000000 120689.000000 0.0 121538.000000 1.215380e+05 1.215380e+05
mean 1.024726 2.060710 6.942860 3.709852 1.753228 1.573877 1.000963 267.391781 435.255564 11050.876802 265.532547 2.687530 1.329658 1.424824 106.509582 NaN 63782.338108 1.986829e+05 5.490437e+05
std 0.264539 0.696957 7.478536 4.011229 1.730277 1.508579 0.039005 83.155851 188.132717 1809.472691 86.032718 1.461307 0.470091 0.494318 1.668715 NaN 40836.244467 1.269200e+04 2.642661e+04
min 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 1.000000 110.000000 110.000000 0.000000 110.000000 1.000000 1.000000 1.000000 104.000000 NaN 1.000000 -1.200176e+04 5.100000e+01
25% 1.000000 2.000000 0.000000 0.000000 0.000000 1.000000 1.000000 200.000000 290.000000 10300.000000 190.000000 1.000000 1.000000 1.000000 105.000000 NaN 30402.250000 1.926279e+05 5.457116e+05
50% 1.000000 2.000000 0.000000 0.000000 2.000000 1.000000 1.000000 270.000000 440.000000 10600.000000 270.000000 4.000000 1.000000 1.000000 107.000000 NaN 60864.500000 2.002344e+05 5.499873e+05
75% 1.000000 2.000000 15.000000 8.000000 4.000000 1.000000 1.000000 340.000000 590.000000 11300.000000 340.000000 4.000000 2.000000 2.000000 108.000000 NaN 91264.750000 2.047577e+05 5.537566e+05
max 4.000000 6.000000 15.000000 35.000000 42.000000 20.000000 3.000000 410.000000 740.000000 18700.000000 410.000000 6.000000 2.000000 2.000000 109.000000 NaN 159620.000000 1.474722e+06 1.179377e+06
df['X좌표']
0         192679.8948
2         194094.3509
3         189576.5582
4         194090.2401
6         204489.9224
             ...     
121548    192718.2324
121549    191212.4266
121550    192699.5937
121551    190746.1785
121552    192708.2449
Name: X좌표, Length: 121538, dtype: float64

X,Y 좌표 변환

  • 위도 경도 좌표계 : WGS84 (ESPG:4326)
  • TM (ESPG:2097)
  • ESPG: 8165 (공공데이터 신호등 자료는 ESPG:8165 좌표계를 따르며 이를 ESPG:4326으로 변경한다.)
# proj1 = pyproj.Proj(init='epsg:8165')
# proj2 = pyproj.Proj(init='epsg:4326')
# fx, fy = pyproj.transform(proj1, proj2, df['X좌표'], df['Y좌표'])

def project_array(coord, p1_type, p2_type):
    """
    좌표계 변환 함수
    - coord: x, y 좌표 정보가 담긴 NumPy Array
    - p1_type: 입력 좌표계 정보 ex) epsg:5179
    - p2_type: 출력 좌표계 정보 ex) epsg:4326
    """
    p1 = pyproj.Proj(init=p1_type)
    p2 = pyproj.Proj(init=p2_type)
    fx, fy = pyproj.transform(p1, p2, coord[:, 0], coord[:, 1])
    return np.dstack([fx, fy])[0]
coord = np.array(df[['X좌표', 'Y좌표']])
coord
array([[192679.8948, 559453.6699],
       [194094.3509, 559522.4508],
       [189576.5582, 553775.811 ],
       ...,
       [192699.5937, 545494.7748],
       [190746.1785, 545409.8107],
       [192708.2449, 545502.1187]])
p1_type = "epsg:5186"
p2_type = "epsg:4326"

# project_array() 함수 실행
result = project_array(coord, p1_type, p2_type)
df['경도'] = result[:, 0]
df['위도'] = result[:, 1]

df.head()
df
df_loc = df[['횡단보도관리번호', '상태 (공통)'  ,'신규정규화ID', '이력ID', '공사관리번호', '구코드 (공통)','위도', '경도']]
df_loc_guro = df_loc[df_loc['구코드 (공통)'] == 530]
df_loc_guro
/root/00_PRJ/blog_group/quarto/gabrielwithappy.github.io/.venv/lib/python3.8/site-packages/pyproj/crs/crs.py:141: FutureWarning:

'+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6

/root/00_PRJ/blog_group/quarto/gabrielwithappy.github.io/.venv/lib/python3.8/site-packages/pyproj/crs/crs.py:141: FutureWarning:

'+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6

/tmp/ipykernel_4713/2905416754.py:14: FutureWarning:

This function is deprecated. See: https://pyproj4.github.io/pyproj/stable/gotchas.html#upgrading-to-pyproj-2-from-pyproj-1

/tmp/ipykernel_4713/4265179734.py:6: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

/tmp/ipykernel_4713/4265179734.py:7: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
횡단보도관리번호 상태 (공통) 신규정규화ID 이력ID 공사관리번호 구코드 (공통) 위도 경도
173 06-0000005482 1.0 1152694 33837 2008-0112-847 530.0 37.488290 126.858558
182 06-0000005553 1.0 NaN 2287 2000-0000-000 530.0 37.502715 126.862302
523 06-0000029865 1.0 NaN 40287 2010-0108-038 530.0 37.483324 126.841663
524 06-0000029865 1.0 NaN 67482 2010-0108-038 530.0 37.483175 126.841876
525 06-0000029865 1.0 NaN 72274 2010-0108-038 530.0 37.483175 126.841876
... ... ... ... ... ... ... ... ...
121442 06-0000054175 1.0 1154231.0 159505 NaN 530.0 37.494838 126.856403
121456 06-0000054176 1.0 1154232.0 159506 NaN 530.0 37.494730 126.856263
121458 06-0000006482 1.0 2107192.0 31834 2004-0108-210 530.0 37.510976 126.884303
121501 06-0000041080 1.0 2131078.0 110540 NaN 530.0 37.482978 126.900314
121505 06-0000029242 1.0 NaN 33251 2000-0000-000 530.0 37.495085 126.858776

5215 rows × 8 columns

df_loc_guro = df_loc_guro.drop_duplicates(['신규정규화ID'])
# df_loc_guro = df_loc_guro.drop_duplicates(['공사관리번호'])
_df = df[(df['상태 (공통)'] != 1)]
from folium.plugins import HeatMap
import branca.colormap as cm
from collections import defaultdict

center = [37.53165351203043, 126.9974246490573]
tiles = "http://mt0.google.com/vt/lyrs=m&hl=ko&x={x}&y={y}&z={z}"
m = folium.Map(location=center, tiles= tiles, attr="Google", zoom_start =14)

colormap = cm.LinearColormap(colors=[ 'red', 'yellow','blue', 'green'], vmin=0, vmax=100)
colormap.caption = 'HeatMap Intensity'


# 1. Draw SafeZone (HeatMap)
df_raw_safezone = pd.read_csv('어린이보호구역_위치도.csv', encoding='cp949')
df_raw_safezone.rename(columns={'x좌표':'경도', 'y좌표':'위도'}, inplace = True)

_df_safezone = df_raw_safezone[['위도', '경도']].copy()
_df_safezone.loc[:,'value'] = 100
for _, row in _df_safezone.iterrows():
    lat, lon = row['위도'], row['경도']
    folium.Circle(location=[lat, lon],  tooltip='safezone', color='lightgreen', fill=True ).add_to(m)



# 2. Draw CCTV
df_raw_cctv = pd.read_csv('서울시_강남구_어린이보호구역.csv', encoding='cp949')
df_raw_cctv = df_raw_cctv.dropna(subset=['위도','경도', 'CCTV설치대수'])

_df_cctv = df_raw_cctv[['위도', '경도', 'CCTV설치대수']].copy()
_df_cctv.rename(columns={'CCTV설치대수':'value'}, inplace = True)
_df_cctv.head(3)
for _, row in _df_cctv.iterrows():
    lat, lon = row['위도'], row['경도']
    folium.Circle(location=[lat, lon], tooltip='cctv', color='green', fill=True).add_to(m)



# 4. Draw crosswalk
nosignal = 0.1
df_raw_crosswalk = pd.read_csv('서울특별시_성동구_횡단보도.csv', encoding='cp949')
df_raw_crosswalk.rename(columns={'X좌표(경도)':'경도', 'Y좌표(위도)':'위도'}, inplace = True)
df_raw_crosswalk.head(1)
df_raw_crosswalk = df_raw_crosswalk[['위도','경도','보행자신호등 유무']]
df_raw_crosswalk.loc[:,'value'] = df_raw_crosswalk['보행자신호등 유무'].replace({'N':nosignal, 'Y':0})
df_crosswalk = df_raw_crosswalk[['위도', '경도', 'value']]
display(df_crosswalk)
for _, row in df_crosswalk.iterrows():
    lat, lon = row['위도'], row['경도']
    if row['value'] == nosignal:
        folium.CircleMarker(location=[lat, lon], tooltip='신호등 없는 횡단보도', max_level=13, color='red', redius=1,  fill=True, fill_opacity=0.1, opacity=0).add_to(m)


# Draw HeatMap
_df_heatmap = pd.concat([_df_safezone, _df_cctv])
_df_heatmap_negative = df_crosswalk

_df_heatmap = _df_heatmap
HeatMap(_df_heatmap.values.tolist(),
        radius = 20,
        blur=20,
        min_opacity=0.5,
        # max_zoom=5,
        gradient = {0:'red', 0.25:'yellow',0.5:'blue', 0.9:'lightgreen', 1:'green'} ).add_to(m)
colormap.add_to(m)

# HeatMap(_df_heatmap_negative.values.tolist(),
#         radius = 5,
#         blur=20,
#         min_opacity=0.5,
#         # max_zoom=5,
#         gradient = {1:'red'} ).add_to(m)
# colormap.add_to(m)

# 1. Draw School
df_element_raw = pd.read_csv('./element_info.csv')
_df_school = df_element_raw.dropna(subset=['위도','경도'])
for _, row in _df_school.iterrows():
    lat, lon = row['위도'], row['경도']
    folium.Circle(location=[lat, lon], popup=row['학교명'], color='black', fill=True ).add_to(m)

m
위도 경도 value
0 37.561306 127.035717 0.0
1 37.562108 127.033961 0.1
2 37.562864 127.032547 0.0
3 37.562930 127.032486 0.1
4 37.544121 127.063398 0.0
... ... ... ...
982 37.544061 127.057766 0.1
983 37.543682 127.059001 0.1
984 37.543254 127.060418 0.1
985 37.545279 127.061395 0.1
986 37.545704 127.059941 0.1

987 rows × 3 columns

Make this Notebook Trusted to load map: File -> Trust Notebook