7-2. 한국복지패널 데이터 분석(2)

🔗 'Do it! 쉽게 배우는 파이썬 데이터 분석' 책을 기반으로 JupyterLab 환경에서 학습한 내용입니다 _φ(๑╹╹๑)

 

📌 직업별 월급 차이


 

  • 직업 변수 검토 및 전처리
# 타입 확인
welfare['code_job'].dtypes

# 값 특징 및 이상치 확인
welfare['code_job'].value_counts()

# 4자리로 구성된 직종코드에서 4자리를 초과하거나 모름/무응답에 해당하는 9999 존재 확인
# 존재한다면 결측 처리 필요
# 불필요한 검색 과정을 방지하기 위해, 결측을 처리한 후 다른 데이터프레임과 결합하는 순서 추천
welfare['code_job'].max()

""" 
welfare 데이터프레임에서 직업 분류 코드가 어떤 직업을 의미하는지 확인하기 쉽도록
직업 분류 코드별 직업명을 담고 있는 데이터를 불러온 후, welfare 데이터프레임과 결합
"""
list_job = pd.read_excel('Koweps_Codebook_2019.xlsx', sheet_name = '직종코드')
list_job.head()
welfare = welfare.merge(list_job, how = 'left', on = 'code_job')

"""
code_job에 값이 있지만 분류표에 해당하는 직업이 없어 job이 결측이 된 경우가 있는지 결측치 개수를 비교하여 확인
* 책에는 없지만, job에 결측값이 언제 생성되는지에서 출발 
* 경우1. code_job이 결측인 경우
* 경우2. code_job에 값이 있지만 분류표에 누락된 경우

직업별 월급을 추출할 때, 9999를 제외한 4자리 직업 분류 코드가 있다면 직업이 존재한다는 의미가 아닐까?
결측값의 개수가 다르다면 분류표에 누락된 직업이 없는지 확인해보는 것이 어떨까?
"""
print(welfare['code_job'].isna().sum())
print(welfare['job'].isna().sum())

# 데이터프레임 결합 확인
welfare.dropna(subset = ['code_job'])[['code_job', 'job']].head()

 

 

  • 직업별 월급 차이 확인
# 직업별 월급 평균을 확인할 것이므로 직업과 월급의 결측 행 제거

welfare_job_income = welfare.dropna(subset = ['job', 'income'])\
.groupby('job', as_index = False)\
.agg(mean_income = ('income', 'mean'))

welfare_job_income

# 월급 상위 top 10 직업 확인
top10 = welfare_job_income.sort_values('mean_income', ascending = False).head(10)
top10

import matplotlib.pyplot as plt
plt.rcParams.update({'font.family': 'Malgun Gothic'}) # 그래프 한글 깨짐 방지

# 월급 top10 직업별 월급 막대 그래프 생성 (y축이 직업이어야 각 직업명이 겹치지 않고 출력)
sns.barplot(data = top10, x = 'mean_income', y = 'job', hue = 'job')

# 월급 하위 10개 직업 확인
bottom10 = welfare_job_income.sort_values('mean_income').head(10)
bottom10

# 월급 하위 10개 직업별 월급 막대 그래프 생성
sns.barplot(data = bottom10, x = 'mean_income', y = 'job', hue = 'job')\
.set(xlim = (0, 800)) # top10과 비교 용이하도록 축 범위 설정

 

  • 분석 결과
    • 월급이 가장 많은 직업은 의료 진료 전문가이며 평균 781만원을 받는다.
    • 월급이 가장 적은 직업은 기타 돌봄·보건 및 개인 생활 서비스 종사자이며  평균 73만원을 받는다.
    • 의료 진료 전문가는 기타 돌봄·보건 및 개인 생활 서비스 종사자의 평균 10배가 넘는 월급을 받는다.

 

 

 

📌 성별 직업 빈도


  • 직업 변수 검토 및 전처리
    • 위의 '직업별 월급 차이 분석'에서 진행

 

  • 성별 직업 빈도 확인
# 남성 직업 빈도 상위 10개 추출

job_male = welfare.dropna(subset = ['job'])\
.query('sex == "male"')\
.groupby('job', as_index = False)\
.agg(n = ('job', 'count'))\
.sort_values('n', ascending = False)\
.head(10)

job_male

# 남성 직업 빈도 상위 10개 막대 그래프 생성
sns.barplot(data = job_male, x = 'n', y = 'job', hue = 'job').set(xlim = (0, 500)) # 비교를 위해 여성, 남성 동일한 축 범위 지정

# 여성 직업 빈도 상위 10개 추출
job_female = welfare.dropna(subset = ['job'])\
.query('sex == "female"')\
.groupby('job', as_index = False)\
.agg(n = ('job', 'count'))\
.sort_values('n', ascending = False)\
.head(10)

job_female

# 여성 직업 빈도 상위 10개 막대 그래프 생성
sns.barplot(data = job_female, x = 'n', y = 'job', hue = 'job').set(xlim = (0, 500))

 

  • 분석 결과
    • 남성과 여성 모두 작물 재배 종사자가 가장 많다.
    • 남성은 작물 재배 종사자 뒤로 자동차 운전원, 경영 관련 사무원, 매장 판매 종사자 순으로 많다.
    • 여성은 작물 재배 종사자 뒤로 청소원 및 환경미화원, 매장 판매 종사자, 회계 및 경리 사무원 순으로 많다.

 

 

 

📌 종교 유무에 따른 이혼율


  • 종교 변수 검토 및 전처리
# 타입 확인
welfare['religion'].dtypes

# 값 특징 및 이상치 확인
welfare['religion'].value_counts()

# 종교 변수 결측 개수 확인
welfare['religion'].isna().sum()

# 값의 의미를 이해하기 쉽도록 종교 변수 값 1인 경우 'yes', 2인 경우 'no'로 변경 (값 의미: 코드북 참고)
welfare['religion'] = np.where(welfare['religion'] == 1, 'yes', 'no')

# 값 변경 확인
welfare['religion'].value_counts()

 

  • 혼인 변수 검토 및 전처리
# 타입 확인
welfare['marriage_type'].dtypes

# 값 특징 및 이상치 확인
welfare['marriage_type'].value_counts()

# 혼인 변수 결측 개수 확인
welfare['marriage_type'].isna().sum()

# 변수 생성: marriage_type 값에 따라 유배우, 이혼, 그 외로 분류 (값 의미: 코드북 참고)
welfare['marriage'] = np.where(welfare['marriage_type'] == 1, 'marriage', np.where(welfare['marriage_type'] == 3, 'divorce', 'etc'))

# 이혼 여부별 빈도
n_divorce = welfare.groupby('marriage', as_index = False)\
.agg(n = ('marriage', 'count'))

n_divorce

 

  • 종교 유무에 따른 이혼율 확인
# 종교별 이혼 여부 확인
rel_div = welfare.query('marriage != "etc"')\
.groupby('religion', as_index = False)\
['marriage']\
.value_counts(normalize = True)

rel_div

"""
코드 해석
1. welfare.query('marriage != "etc"'): 유배우와 이혼 행만 추출
- 종교가 이혼 여부에 영향을 줄 수 있는가?가 분석 목표!
- 별거는 이혼 여부가 애매하므로 제외!
- 사별은 사망에 의한 것으로 종교에 따른 이혼 O, X를 선택할 기회가 박탈되었으므로 제외!
2. groupby('religion', as_index = False): 종교별 그룹화
3. ['marriage']: 종교별로 그룹화 된 상태에서 각 그룹에서 marriage 변수 열의
4. value_counts(normalize = True): 값에 따른 비율 계산

Q) 왜 전체에서 각각의 이혼 비율을 계산하는 것이 아니라 각 종교 유무마다 이혼의 비율을 계산할까?
A) 종교가 있는 사람의 수가 단순히 많다면, 그냥 종교 있는 사람의 이혼율이 무조건 높다고 나옴
"""

# 이혼인 행만 추출하여 백분율 % 값 소수점 첫 번째 자리까지 변경
rel_div = rel_div.query('marriage == "divorce"')\
.assign(proportion = round(rel_div[proportion] * 100, 1))

rel_div

 

  • 분석 결과
    • 이혼율은 종교가 있으면 8.0% 종교가 없으면 9.5%로 종교가 있는 사람이 이혼을 덜 한다.

 

 

📌 연령대 및 종교 유무에 따른 이혼율


  • 연령대 변수 검토 및 전처리
  • 종교 변수 검토 및 전처리
    • 위의 '종교 유무에 따른 이혼율' 분석에서 진행

 

  • 연령대별 이혼율 확인
age_div = welfare.query('marriage != "etc"')\
.groupby('ageg', as_index = False)\
['marriage']\
.value_counts(normalize = True)

age_div

# 연령대별 빈도 확인
welfare.query('marriage != "etc"')\
.groupby('ageg', as_index = False)\
['marriage']\
.value_counts()
# 출력 결과: 초년층의 표본이 너무 작아 초년층을 대표할 수 없으므로 비교 대상에서 제외

# 중년층, 노년층 이혼인 행만 추출하여 백분율 % 값 소수점 첫 번째 자리까지 변경
age_div = age_div.query('ageg != "young" & marriage == "divorce"')\
.assign(proportion = round(age_div['proportion'] * 100, 1))

age_div

 

  • 연령대 및 종교 유무에 따른 이혼율 확인
# 연령대 및 종교별 이혼율 확인
age_rel_div = welfare.query('marriage != "etc" & ageg != "young"')\
.groupby(['ageg', 'religion'], as_index = False)\
['marriage']\
.value_counts(normalize = True)

age_rel_div

# 이혼인 행만 추출하여 백분율 % 값 소수점 첫 번째 자리까지 변경
age_rel_div = age_rel_div.query('marriage == "divorce"')\
.assign(proportion = round(age_rel_div['proportion'] * 100, 1))

age_rel_div

# 연령대 및 종교별 이혼율 막대 그래프 생성
sns.barplot(data = age_rel_div, x = 'ageg', y = 'proportion', hue = 'religion')

 

  • 분석 결과
    • 중년은 1.3%, 노년은 1.8% 정도로 종교가 없는 사람의 이혼율이 더 높다.

 

 

 

📌 지역별 연령대 비율


 

  • 지역 변수 검토 및 전처리
# 타입 확인
welfare['code_region'].dtypes

# 값 특징 및 이상치 확인
welfare['code_region'].value_counts()

# 지역 변수 결측 개수 확인
welfare['code_region'].isna().sum()

""" 
welfare 데이터프레임에서 지역 코드가 어떤 지역을 의미하는지 확인하기 쉽도록
지역 코드 목록을 만든 후, welfare 데이터프레임과 결합
(값 의미: 코드북 참고)
"""
list_region = pd.DataFrame({'code_region': [1, 2, 3, 4, 5, 6, 7],
                           'region': ['서울',
                                     '수도권(인천/경기)',
                                     '부산/경남/울산',
                                     '대구/경북',
                                     '대전/충남',
                                     '강원/충북',
                                     '광주/전남/전북/제주도']})

welfare = welfare.merge(list_region, how = 'left', on = 'code_region')
welfare[['code_region', 'region']].head()

 

  • 지역별 연령대 비율 확인
# 지역별 연령대 비율 확인
region_ageg = welfare.groupby('region', as_index = False)\
['ageg']\
.value_counts(normalize = True)

region_ageg

# 백분율 % 값 소수점 첫 번째 자리까지 변경
region_ageg = region_ageg.assign(proportion = round(region_ageg['proportion'] * 100, 1))
region_ageg.head()

 

  • 누적 비율 막대 그래프 생성
    1. 누적 비율 막대 그래프를 생성하기 위한 피벗 만들기(데이터프레임 행, 열 구성 변경): 데이터프레임의 pivot(index = '변수명', columns = '변수명', values = '변수명') 함수 활용
      • 피벗 필요한 이유: 누적 비율 막대 그래프는 한 행의 값을 누적해서 그래프를 표현하므로 이를 명시하기 위함
    2. 피벗의 행, 열 순서 정렬: 데이터프레임의 sort_values('열 이름')[['1번', '2번', ...]] 함수 활용
      • 열 이름의 값이 많은 순서대로 그래프를 생성하고, 각 그래프 내에서는 1번, 2번 순서로 구성
    3. 그래프 생성: 데이터프레임의 plot.barh(stacked = True) 함수 활용
# 피벗 만들기
df_pivot = region_ageg.pivot(index = 'region',
                            columns = 'ageg',
                            values = 'proportion')
df_pivot

"""
코드 해석
1. index: region을 인덱스로 사용
2. columns: 연령대별로 열을 구성
3. values: 각 항목의 값은 비율로
"""

# old 값이 많은 순서대로 그래프 생성, 각 막대는 초년, 중년, 노년 순으로 구성
reorder_df = df_pivot.sort_values('old')[['young', 'middle', 'old']]

# 가로 누적 비율 막대 그래프 생성
reorder_df.plot.barh(stacked = True)

 

  • 분석 결과
    • 대구/경북의 노년층 비율이 가장 높고, 그 뒤로는 강원/충북, 광주/전남/전북/제주도, 부산/경남/울산 순으로 높다.