EDA | 서울시 교통사고 사고유형별 통계

소리·2024년 1월 30일
0

1단계 데이터 프레임 수정

  • 조건1: ['자치구별(1)', '사고유형별(2)'] Column(열)을 삭제
  • 조건2: ['자치구별(2)', '사고유형별(1)'] Column(열)명 변경
    - '자치구별(2)' -> '자치구'
    - '사고유형별(1)' -> '사고유형'
    - '구분별(1)' -> '구분'
df_target.drop(columns = ['자치구별(1)','사고유형별(2)'], inplace=True)
df_target.rename(columns={'자치구별(2)': '자치구', '사고유형별(1)': '사고유형', '구분별(1)': '구분'}, inplace=True)


# 다른방식 df_target.columns = ['자치구', '사고유형', '구분'] + list(df_target.columns[3:])
  • 조건3: '구분' Column(열) Data를 아래와 같이 변경
    - 괄호 및 괄호 안의 내용 삭제
    - 값 앞뒤에 공백(띄어쓰기 등) 삭제
    - 발생건수 (건) -> 발생건수
    - 사망자수 (명) -> 사망자수
    - 부상자수 (명) -> 부상자수
import re
df_target['구분'] = df_target['구분'].apply(lambda x: re.sub(r'\([^)]*\)', '', x).strip())

🙋‍♀️ 앞서 정규표현식을 써서 괄호를 삭제했던 게 기억나서 그 내용을 적용해 봄

그외

# 1-2
def del_bracket(value):
    if '(' in value:
        value = value.split(' ')[0]
        value = value.strip()
        return value
    else:
        return value
df_target.구분 = df_target.구분.apply(del_bracket)

이런 식으로도 품

  • 조건6: ['1988', '1989', ..., '2020', '2021'] Column(열) Data 중 '-'인 Data를 숫자 0(정수형)으로 변경
  • 조건7: ['1988', '1989', ..., '2020', '2021'] Column(열) Data 중 nan인 Data를 숫자 0(정수형)으로 변경
  • 조건8: ['1988', '1989', ..., '2020', '2021'] Column(열) Data 중 전부 숫자로 구성 되어있는 Data의 Type을 정수형으로 변경
#내 풀이
df_target.iloc[:, 3:] = df_target.iloc[:, 3:].replace('-', 0).fillna(0)
df_target.iloc[:, 3:] = df_target.iloc[:, 3:].astype('int')
#모범 답안
# 1-3
def change_na_type(value):
    if value == '-' or type(value) == float:
        return 0
    elif type(value) == str and value.isdigit():
        return int(value)
    else:
        return value

df_target = df_target.applymap(change_na_type)

✏️ 전반적으로 내 풀이가 더 짧아서 뿌듯했다. 다만 코드 효율성은 더 좋은가에 대해서는 확신하지 못함

  • 조건9: '자치구' Column(열) Data 중 '소계'인 Data를 '서울시'로 변경
  • 조건10 : ['자치구', '사고유형', '구분'] 'Column(열)을 Index로 설정
#내 풀이
df_target['자치구'] = df_target['자치구'].replace('소계', '서울시')
#또 다른 방식 df_target.loc[df_target['자치구'] == '소계', '자치구'] = '서울시'

df_target.set_index(['자치구', '사고유형', '구분'], inplace=True)
  • 조건11 : 현재 값이 0인 ['1988', '1989', ..., '2003', '2004'] Column(열)의 '서울시'-'합계'-'발생건수' Row(행) Data를 채워주세요.
    각 자치구('서울시' 포함) '합계'-'발생건수'는 '차대사람'-'발생건수', '차대차'-'발생건수', '차량단독'-'발생건수', '건널목'-'발생건수'의 합입니다.
#내풀이
df_past = df_target.loc[:, :'2004']

for idx in df_past.index.get_level_values(0).unique():
    for col in df_past.columns:
      total_a = 0
      for idx2 in df_past.index.get_level_values(1).unique():
        if idx2 != '합계':
          
          try:
            a = df_past.loc[(idx, idx2, '발생건수'), col].sum()
            total_a += a
          except KeyError:
            pass
          
        df_past.loc[(idx, '합계', '발생건수'), col] = total_a
        print(idx, col, total_a)
        
df_target = pd.concat([df_past, df_target.loc[:,'2005':]], axis=1)

이런 식으로 값이 프린트 되는데 조금 복잡하게 풀었다.
다른 간단한 방식도 이번에 배웠다.

#다른 방식
for idx in df_past.index.get_level_values(0).unique():
    accident_type = df_past.index.get_level_values('사고유형').unique()[1:]:
    df_past.loc[(idx, '합계', '발생건수'), :] = df_past.loc[(idx, accident_type, '발생건수'), :].sum()


# 1-5 모범답안
df_target_year = df_target[df_target.columns[:17]]
idx_level_1_list = df_target_year.loc['서울시'].index.get_level_values(0).unique()
idx_total = sum(df_target_year.loc[('서울시', idx1, '발생건수')] for idx1 in idx_level_1_list if idx1 != '합계')
df_target.loc[('서울시', '합계', '발생건수'), df_target.columns[:17]] = idx_total

2단계 가공 및 추출

  • 조건1: 각 자치구('서울시' 포함) / 사고유형별 '발생건수' Row(행) Data만 추출
df_result = df_target[df_target.index.get_level_values(2)=='발생건수']
df_result = df_result.droplevel(level=2)
  • 조건2: 각 자치구('서울시' 포함) / 사고유형별 '사망자수' Row(행) Data만 추출
  • 조건3: '구분' Index를 제거
  • 조건4: Index는 아래와 같이 변경
    • '자치구'와 '사고유형'의 위치를 바꾸어주세요.
    • '사고유형' Index는 아래 type_list의 순서와 동일하게 정렬해주세요.
    • '자치구' Index는 아래 gu_list의 순서와 동일하게 정렬해주세요.
    • '사고유형' Index를 우선하여 정렬하여 주세요.
#내 풀이
df_result = df_target.loc[(slice(None), slice(None), '사망자수'), :]

#구분 제거
df_result = df_result.droplevel(2)

#자치구와 사고유형 위치 변경
df_result = df_result.swaplevel(0, 1, axis=0)

#사고유형 인덱스는 type_list와 동일하게 정렬
df_result= df_result.loc[pd.IndexSlice[type_list, :], :]

#조건엔 없고 사진에 있는 
df_result = df_result.loc[:,'2005':]
#모범답안

 2-2
# 방법1: sort_index 사용
type_order = {idx1: i for i, idx1 in enumerate(type_list)}

df_result = df_target.loc[df_target.index.get_level_values(2)=='사망자수', df_target.columns[17:]]
df_result = df_result.droplevel(level=2)
df_result = df_result.swaplevel(0, 1)

df_result = df_result.sort_index(key=lambda x: x.map(type_order))

check_02_02(df_result)
display(df_result)

# 방법2: 직접 index 순서 지정
df_result = df_target.loc[df_target.index.get_level_values(2)=='사망자수', df_target.columns[17:]]
df_result = df_result.droplevel(level=2)
df_result = df_result.swaplevel(0, 1)

idx_tuple_list = [(idx1, idx2) for idx1 in type_list for idx2 in gu_list if (idx1, idx2) in df_result.index]
df_result = df_result.loc[[tp for tp in idx_tuple_list if tp in df_result.index]

3단계 원하는 정보 얻기

  • 조건1: 2005년부터 2021년까지 각 자치구('서울시' 포함) / 사고유형별 '사망률'을 구하기
    • '사망률' = '사망자수' / '발생건수' * 100
    • 소숫점 셋째자리에서 반올림하여 두번째자리까지 표기
    • 특정 자치구의 사고유형 중 '사망자수' 또는 '발생건수'가 없다면 계산하지 않음
df_target3 = df_target.copy()
df_target3 = df_target3.loc[:, '2005':]
df_target3 = df_target3.loc[(slice(None), slice(None), ['발생건수', '사망자수']), :].sort_index()
df_target3 = df_target3.loc[df_target3.index.get_level_values(1) != '건널목', :]

result_list = []

for idx in df_target3.index.get_level_values(0).unique():
    for col in df_target3.columns:

      for idx2 in df_target3.index.get_level_values(1).unique():
        try:
          num = df_target3.loc[(idx, idx2, '사망자수'), col]
          den = df_target3.loc[(idx, idx2, '발생건수'), col]
          
          if (num != 0) or (dem !=0):
            rate = round(num / den * 100, 2)
        
        except:
          rate = 0
        
        result_list.append([idx, idx2, col, rate])    

result_df = pd.DataFrame(result_list, columns=['자치구', '사고유형', '년도', '비율'])       
df_result = pd.pivot_table(result_df, index = ['자치구', '사고유형'], columns=['년도'], values='비율').rename_axis(columns=None)
df_result = df_result.loc[pd.IndexSlice[gu_list, type_list, :], :]
#모범답안
df_result = df_target.loc[df_target.index.get_level_values(2).isin(['발생건수', '사망자수']), df_target.columns[17:]]

for gu in gu_list:
    for type_ in type_list:
        idx_dead = (gu, type_, '사망자수')
        idx_total = (gu, type_, '발생건수')
        if idx_dead in df_result.index and idx_total in df_result.index:
            df_result.loc[(gu, type_, '사망률')] = (df_result.loc[(gu, type_, '사망자수')] / df_result.loc[(gu, type_, '발생건수')] * 100).apply(lambda x: round(x, 2))


df_result = df_result.loc[df_result.index.get_level_values(2) == '사망률']
df_result = df_result.droplevel(level=2)
profile
데이터로 경로를 탐색합니다.

0개의 댓글