보행자 사망 교통사고 분석을 통한 현행제도 개선 가이드라인

김도원·2023년 6월 7일
0
post-thumbnail

프로젝트 요약

안전속도 5030 시행 후 2년이 지났음에도 여전히 실효성에 대한 논쟁이 진행 중이며, 거센 여론에 일부 시군구에서는 야간에 제한 속도를 상향하는 등 정책을 수정 시행할 예정
안전속도 5030 정책의 실효성을 확인 후 교통안전에 대한 중요한 요소를 분석하여 보완해야 할 점 제공 및 향후 교통 정책 수립에 대한 가이드라인을 제공하고자 한다.

박무, 연무 등이 자주 발생하고 시야 확보가 어려운 새벽 시간대에도 정책 유지
과속 단속 카메라 1대당 사망자 분포가 높은 곳에 단속 카메라 추가 설치 권고

역할

1. 빅쿼리에 데이터를 취합하였습니다.

2. 빅쿼리에서 데이터를 받아 파이썬에서 쿼리 작성하여 복합 누적막대바 선차트, 원 비중차트 등을 시각화 하였습니다.

image.jpg1image.jpg2
image.jpg3image.jpg4
날씨 조건에 따른 사고발생 비중 코드

import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
from google.cloud import bigquery

font_path = r'D:\폰트\Nanum_Gothic\NanumGothic.ttf'
fontprop = fm.FontProperties(fname=font_path, size=12)
#### bigquery json 입력
client = bigquery.Client.from_service_account_json(r'.json')

target_year = "2022"

query = f"""
SELECT
  weather AS Weather_Condition,
  SUM(Death_Toll) AS Death_Toll,
  SUM(Serious_Injury) AS Serious_Injury,
  SUM(Minor_Injury) AS Minor_Injury,
  SUM(Injury_Report) AS Injury_Report
FROM `road-traffic-safety-388112.Traffic_Accidents.Weather`
WHERE years = {target_year}
GROUP BY weather;
"""

job = client.query(query)
results = job.result()

weather_conditions = []
death_rate = []
serious_rate = []
minor_rate = []
report_rate = []

for row in results:
    weather = row['Weather_Condition']
    death_toll = row['Death_Toll']
    serious_injury = row['Serious_Injury']
    minor_injury = row['Minor_Injury']
    injury_report = row['Injury_Report']
    total = death_toll + serious_injury + minor_injury + injury_report

    weather_conditions.append(weather)
    death_rate.append((death_toll / total) * 100)
    serious_rate.append((serious_injury / total) * 100)
    minor_rate.append((minor_injury / total) * 100)
    report_rate.append((injury_report / total) * 100)

x = range(len(weather_conditions))

plt.bar(x, death_rate, label='사망자', color='#e40615' )
plt.bar(x, serious_rate, bottom=death_rate, label='중상자', color='#003f7d')
plt.bar(x, minor_rate, bottom=[death_rate[i] + serious_rate[i] for i in x], label='경상자', color='#f8be31')
plt.bar(x, report_rate, bottom=[death_rate[i] + serious_rate[i] + minor_rate[i] for i in x], label='부상신고자', color='#fd7702')

plt.ylabel('누적 비중(%)', fontproperties=fontprop)
plt.title(f'날씨 조건에 따른 사고 발생 비중 ({target_year})', fontproperties=fontprop, fontsize=16)
plt.xticks(x, weather_conditions, fontproperties=fontprop)
plt.legend(prop=fontprop, bbox_to_anchor=(1.02, 1), loc='upper left')

plt.show()
서울시 연도별 사고발생 비중 코드
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
from google.cloud import bigquery

font_path = r'D:\폰트\Nanum_Gothic\NanumGothic.ttf'
fontprop = fm.FontProperties(fname=font_path, size=12)

client = bigquery.Client.from_service_account_json(r'.json')



query = f"""
SELECT years AS years_Condition,
  SUM(Death_Toll) AS Death_Toll,
  SUM(Serious_Injury) AS Serious_Injury,
  SUM(Minor_Injury) AS Minor_Injury,
  SUM(Injury_Report) AS Injury_Report
FROM `road-traffic-safety-388112.Traffic_Accidents.Pedestrian_Jaywalking_Seoul` 
GROUP BY years
ORDER BY years ASC;
"""

job = client.query(query)
results = job.result()

years_conditions = []
death_rate = []
serious_rate = []
minor_rate = []
report_rate = []

for row in results:
    years = row['years_Condition']
    death_toll = row['Death_Toll']
    serious_injury = row['Serious_Injury']
    minor_injury = row['Minor_Injury']
    injury_report = row['Injury_Report']
    total = death_toll + serious_injury + minor_injury + injury_report

    years_conditions.append(years)
    death_rate.append((death_toll / total) * 100)
    serious_rate.append((serious_injury / total) * 100)
    minor_rate.append((minor_injury / total) * 100)
    report_rate.append((injury_report / total) * 100)

x = range(len(years_conditions))
bar_width= 0.4
plt.bar(x, death_rate, label='사망자', width=bar_width, color='#e40615' )
plt.bar(x, serious_rate, bottom=death_rate, label='중상자', width=bar_width, color='#003f7d')
plt.bar(x, minor_rate, bottom=[death_rate[i] + serious_rate[i] for i in x], label='경상자', width=bar_width, color='#f8be31')
plt.bar(x, report_rate, bottom=[death_rate[i] + serious_rate[i] + minor_rate[i] for i in x], label='부상신고자', width=bar_width, color='#fd7702')


plt.ylabel('누적 비중(%)', fontproperties=fontprop)
plt.title(f'서울시 연도별 사고 발생 비중', fontproperties=fontprop, fontsize=16)
plt.xticks(x, years_conditions, fontproperties=fontprop)
for i, (d, s, m, r) in enumerate(zip(death_rate, serious_rate, minor_rate, report_rate)):
    plt.text(i, d/2, f"{d:.1f}%", ha='center', color='white')
    plt.text(i, d + s/2, f"{s:.1f}%", ha='center', color='white')
    plt.text(i, d + s + m/2, f"{m:.1f}%", ha='center', color='black')
    plt.text(i, d + s + m + r/2, f"{r:.1f}%", ha='center', color='black')
    
plt.plot(x, serious_rate, color='lightgreen', marker='o', label='중상자', linewidth=2)
plt.plot(x, minor_rate, color='#f8be31', marker='o', label='경상자', linewidth=2)
plt.legend(prop=fontprop, bbox_to_anchor=(1.02, 1), loc='upper left')

plt.show()
연도별 횡단사고 치사율 코드
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
from google.cloud import bigquery

font_path = r'D:\폰트\Nanum_Gothic\NanumGothic.ttf'
fontprop = fm.FontProperties(fname=font_path, size=12)
#### bigquery json 입력
client = bigquery.Client.from_service_account_json(r'.json')

query1 = """
SELECT years,
    SUM(death_toll) AS death_toll,
    SUM(counts) AS counts,
    SUM(death_toll) / SUM(counts) * 100 AS death_per
FROM `road-traffic-safety-388112.Traffic_Accidents.Pedestrian_Type_Seoul`
WHERE accident_type = '횡단중'
GROUP BY years
"""
query_job1 = client.query(query1)

results1 = query_job1.result()

values = {}
for row in results1:
    year = row['years']
    death_toll = row['death_toll']
    counts = row['counts']
    values[year] = (death_toll, counts)

query2 = """
SELECT years,
    SUM(death_toll) AS death_toll,
    SUM(counts) AS counts,
    SUM(death_toll) / SUM(counts) * 100 AS death_per
FROM `road-traffic-safety-388112.Traffic_Accidents.Pedestrian_Jaywalking_Seoul`
GROUP BY years
"""
query_job2 = client.query(query2)

results2 = query_job2.result()

years1 = []
death_per_values1 = []
years2 = []
death_per_values2 = []

for row in results2:
    year = row['years']
    death_toll = row['death_toll']
    counts = row['counts']
    if year in values:
        diff_death_toll = values[year][0] - death_toll
        diff_counts = values[year][1] - counts
        years1.append(year)
        death_per_values1.append(row['death_per'])
        years2.append(year)
        death_per_values2.append(diff_death_toll / diff_counts * 100)

bar_width = 0.3
bar1_positions = [year - bar_width/2 for year in years1]
bar2_positions = [year + bar_width/2 for year in years2]

plt.bar(bar1_positions, death_per_values1, color='#e40615', width=bar_width, label='횡단보도 외')
plt.bar(bar2_positions, death_per_values2, color='#003f7d', width=bar_width, label='횡단보도 내')

plt.ylabel('치사율(%)', fontproperties=fontprop)
plt.title('연도별 횡단 사고 치사율', fontproperties=fontprop, fontsize=16)
plt.xticks([2019, 2020, 2021, 2022], ['2019', '2020', '2021', '2022'], fontproperties=fontprop, fontsize=12)
plt.legend(prop=fontprop)
plt.show()
서울시 가해 운전자 성별 비중 코드
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
from google.cloud import bigquery
#### bigquery json 입력
font_path = r'D:\폰트\Nanum_Gothic\NanumGothic.ttf'
fontprop = fm.FontProperties(fname=font_path, size=12)
#### bigquery json 입력
client = bigquery.Client.from_service_account_json(r'.json')


query = """
SELECT year,
    gender,
    death_toll,
    serious_injury,
    minor_injury,
    injury_report

FROM `road-traffic-safety-388112.Traffic_Accidents.Seoul_Perpetrator_Gender`
WHERE gender != '기타불명'
"""
query_job = client.query(query)
results = query_job.result()
colors = [ '#003f7d', '#e40615', '#f8be31', '#fd7702', '#666a73','lightblue','lightyellow']
# Store the results in lists
gender_list = []
death_toll_list = []
for row in results:
    gender_list.append(row.gender)
    death_toll_list.append(row.death_toll)

# Plotting the pie chart for age
plt.figure(figsize=(8, 6))
plt.pie(death_toll_list, labels=gender_list, autopct='%1.1f%%',textprops={'fontproperties': fontprop}, colors = colors)
plt.title('서울시 사망 사고 가해 운전자 성별 비중 (2022)', fontproperties=fontprop).set_fontsize(16)

plt.show()

3. 가설 "가시거리가 짧아지면 사고 치사율이 올라갈 것이다." , "횡단보도외 횡단 가시거리의 연관성" 글과 데이터를 작성하였습니다.

사고의 비중은 맑은 날씨에서 90%를 차지하며, 안개는 0.1%에 그치지만 전체 사망자 비율에서는 안개가 절반을 차지하고 있습니다. 이는 흐림, 눈, 비 등 가시거리 확보가 힘든 날씨에서 사망사고가 더 자주 발생한다는 것을 시사합니다. 중상자와 경상자 비율을 살펴보면, 안개 날씨에서는 사고가 발생할 경우 중상자가 크게 나타나는 경향이 있습니다. 또한, 시간대별 사고 대비 사망자 비율을 선 그래프로 분석해보면, 야간 시간대에서의 치사율이 주간 시간대보다 2배에서 5배 정도 높은 것을 확인할 수 있습니다. 이러한 이유로 가시거리 증가를 위한 보조 장비의 중요성이 강조되며, 안개등과 전조등을 키고 안전거리를 최대한 유지하며 속도를 줄이는 등 운전자는 기상이 안 좋을 때 적절한 운전 방법을 채택해야 합니다. 또한, 청각 정보를 활용하여 사고 예방에 효과적으로 기여할 수 있습니다.
야간시간에 속도제한을 풀어주는 예외 조례(법령)을 만드는 것에 반대한다.

횡단보도 내 사고와 횡단보도 외 사고의 치사율 비교 결과, 횡단보도 외 사고의 치사율이 높은 것으로 확인되었습니다. 이는 운전자들이 횡단보도가 있는 지점에서는 주의를 기울이고 감속하는 경향이 있기 때문입니다. 그러나 일반 주행 상황에서 예기치 못한 보행자 출연으로 인해 감속하지 못한 상황에서 사고가 발생할 수 있습니다.
그러므로 운전자의 일반 주행 속도 자체를 줄이는 정책은 횡단보도 외 사고의 치사율을 줄이는 데 상당한 영향을 미칠 수 있다고 볼 수 있습니다. 일반 도로에서의 속도 감속은 운전자의 반응 시간을 늘리고 사고 발생 시 충격을 완화시킬 수 있어 사망이나 중상을 예방하는 데 도움이 됩니다.
그러므로 속도를 줄이는 정책의 중요성을 강조하고, 운전자들에게는 일반 주행 상황에서도 안전속도를 유지하도록 교육하는 것이 필요합니다. 이는 사고 발생 가능성을 감소시키고 보행자와 운전자의 안전을 향상시키는 데 도움이 될 것입니다.

4. Notion 으로 제작과정 공유

기술스택

  • PYTHON

  • SQL

  • BigQuery

  • Matplotlib

  • Numpy

결과

최종 결과물은 PPT 파일로 제작 했습니다.



profile
그냥 사는 사람

0개의 댓글