ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [2월 2주차-2/12(3)]한국복지패널데이터로 한국인의 삶을 분석해보자! 🧐
    Why Not SW CAMP 5기/수업 기록 2025. 2. 13. 10:37

    안녕하세요! 오늘은 한국복지패널데이터(Koweps) 를 활용해 한국인의 삶을 데이터 분석을 통해 살펴보려고 합니다. 한국복지패널데이터는 가구 및 개인의 경제활동, 생활실태, 복지 욕구 등을 연구하기 위해 구축된 대규모 데이터로, 800개 이상의 변수로 구성되어 있어 굉장히 방대한 자료입니다.

    데이터 분석을 통해 다음과 같은 궁금증을 해결해 보겠습니다!

    성별에 따른 월급 차이는 존재할까?
    나이와 월급의 관계는 어떨까?
    연령대별 평균 월급은 어떻게 다를까?
    직업별로 월급은 얼마나 차이가 날까?
    종교 유무에 따라 이혼율이 다를까?
    지역별 연령대 비율은 어떤 패턴을 보일까?


    🔹 1. 데이터 준비하기 📊

    분석을 위해 먼저 데이터를 불러오고, 주요 변수들을 확인해 보겠습니다.

    📌 데이터 불러오기

    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    # 한국복지패널데이터 불러오기
    raw_welfare = pd.read_spss('./data/Koweps_hpwc14_2019_beta2.sav')
    
    # 복사본 생성
    welfare = raw_welfare.copy()
    

    데이터를 살펴보면 총 14,418개 행830개 컬럼으로 구성되어 있음을 알 수 있습니다.

    welfare.shape  # (14418, 830)
    welfare.info()  # 변수 타입 및 결측치 확인
    

    📌 주요 변수 선택 및 이름 변경

    데이터에서 우리가 분석에 활용할 주요 변수들을 선정하고, 이해하기 쉽게 변수명을 변경하겠습니다.

    welfare = welfare.rename(columns={
        'h14_g3': 'sex',           # 성별
        'h14_g4': 'birth',         # 태어난 연도
        'h14_g10': 'marriage_type', # 혼인 상태
        'h14_g11': 'religion',     # 종교 유무
        'p1402_8aq1': 'income',    # 월급
        'h14_eco9': 'code_job',    # 직업 코드
        'h14_reg7': 'code_region'  # 지역 코드
    })
    

    이제 데이터를 본격적으로 분석해 보겠습니다! 🚀


    🔹 2. 성별에 따른 월급 차이 분석

    📌 성별 데이터 전처리

    먼저 성별 데이터를 확인해 보면, 1(남성), 2(여성)으로 기록되어 있습니다. 이를 'male', 'female'로 변환하겠습니다.

    # 1. 변수 검토: 타입 파악, 범주마다 몇 명?
    welfare['sex'].dtypes # dtype('float64')
    
    # 항목별 개수 -> 이상치 확인 가능
    welfare['sex'].value_counts()
    '''
    sex
    2.0    7913
    1.0    6505
    Name: count, dtype: int64
    '''
    
    # 성별 항목에 이름 부여
    welfare['sex'] = np.where(welfare['sex'] ==1, 'male', 'female')
    welfare['sex'].value_counts()
    '''
    sex
    female    7913
    male      6505
    Name: count, dtype: int64

    이제 성별 빈도를 시각화해 보겠습니다.

    sns.countplot(data=welfare, x='sex')
    plt.show()
    

    📌 월급 데이터 전처리

    월급(income) 데이터를 확인해 보니 결측치가 많습니다. 먼저 결측치를 제거하고 월급 분포를 살펴보겠습니다.

    welfare['income'].isna().sum()  # 9,884개 결측치 확인
    
    # 결측치 제거 후 평균 월급 계산
    sex_income = welfare.dropna(subset=['income']).groupby('sex', as_index=False).agg(mean_income=('income', 'mean'))
    
    '''
          sex  mean_income
    0  female   186.293096
    1    male   349.037571
    '''
    sns.barplot(data=sex_income, x='sex', y='mean_income')
    plt.show()
    

    📌 결과: 남성이 여성보다 평균적으로 더 높은 월급을 받는 것으로 나타났습니다.


    🔹 3. 나이와 월급의 관계

    📌 나이 데이터 변환

    태어난 연도(birth)를 이용해 나이(age) 변수를 생성하겠습니다.

    welfare = welfare.assign(age=2019 - welfare['birth'] + 1)
    

    나이 분포를 확인해 보겠습니다.

    sns.histplot(data=welfare, x='age')
    plt.show()
    

    📌 나이별 평균 월급 분석

    age_income = welfare.dropna(subset=['income']).groupby('age', as_index=False).agg(mean_income=('income', 'mean'))
    
    sns.lineplot(data=age_income, x='age', y='mean_income')
    plt.show()
    

    📌 결과: 50대까지 월급이 증가하다가 이후 감소하는 경향을 보였습니다.


    🔹 4. 연령대 및 성별 월급 차이

    연령대를 청년(30세 미만), 중년(30~59세), 노년(60세 이상) 으로 나누고, 평균 월급을 비교해 보겠습니다.

    # 연령대 변수 만들기
    welfare = welfare.assign(
        ageg=np.where(welfare['age'] < 30, 'young',
                      np.where(welfare['age'] <= 59, 'middle', 'old'))
    )
    
    welfare['ageg'].value_counts()
    '''
    ageg
    old       5955
    middle    4963
    young     3500
    Name: count, dtype: int64
    '''
    
    ageg_sex =  welfare.dropna(subset='income').groupby(['ageg','sex'], as_index = False).agg(mean_income =('income', 'mean'))
    '''
         ageg     sex  mean_income
    0  middle  female   230.481735
    1  middle    male   409.541228
    2     old  female    90.228896
    3     old    male   204.570231
    4   young  female   189.822222
    5   young    male   204.909548
    '''
    
    sns.barplot(data=ageg_sex, x = 'ageg', y='mean_income',
                hue = 'sex',
                order = ['young', 'middle', 'old'])
    
    plt.show()

    📌 결과: 중년층의 평균 월급이 가장 높고, 노년층에서 급격히 감소하는 경향이 나타났습니다.


    🔹 5. 직업별 월급 차이

    직업별 평균 월급을 비교해 보겠습니다.

    # 직업 코드 데이터를 불러와 병합
    list_job = pd.read_excel('./data/Koweps_Codebook_2019.xlsx', sheet_name='직종코드')
    list_job.head()
    '''
       code_job                     job
    0       111  의회 의원∙고위 공무원 및 공공단체 임원
    1       112                기업 고위 임원
    2       121          행정 및 경영 지원 관리자
    3       122         마케팅 및 광고∙홍보 관리자
    4       131       연구∙교육 및 법률 관련 관리자
    '''
    
    welfare = welfare.merge(list_job, how='left', on='code_job')
    
    # 직업별 월급 평균 계산
    job_income = welfare.dropna(subset=['income']).groupby('job', as_index=False).agg(mean_income=('income', 'mean'))
    job_income.head()
    '''
                    job  mean_income
    0       가사 및 육아 도우미    92.455882
    1               간호사   265.219178
    2  감정∙기술영업및중개관련종사자    391.000000
    3      건물 관리원 및 검표원   168.375000
    4    건설 및 광업 단순 종사자   261.975000
    '''
    
    # 상위 10개 직업 시각화
    top10_jobs = job_income.sort_values(by='mean_income', ascending=False).head(10)
    plt.rcParams.update({'font.family': 'Malgun Gothic'})
    sns.barplot(data=top10_jobs, x='mean_income', y='job')
    plt.show()

    📌 결과: 의료 진료 전문가, 법률 전문가 등이 가장 높은 월급을 받는 것으로 나타났습니다.


    🔹 6. 종교 유무에 따른 이혼율

    # 종교 유무 변수 확인
    welfare['religion'] = np.where(welfare['religion'] == 1, 'yes', 'no')
    
    # 결혼 상태 변수 확인
    dm={0:'비해당(18세 미만)',
       1:'유배우',
       2:'사별',
       3:'이혼',
       4:'별거',
       5:'미혼(18세이상, 미혼모 포함)',
       6:'기타(사망 등)'}
    
    welfare['marriage_type'] = welfare['marriage_type'].replace(dm)
    
    # 이혼율 분석
    religion_marriage = welfare.query("marriage_type in ['유배우', '이혼']").groupby(['religion', 'marriage_type'], as_index=False).agg(n = ('marriage_type','count'))
    
    '''
      religion marriage_type     n
    0        N           유배우  3660
    1        N            이혼   384
    2        Y           유배우  3530
    3        Y            이혼   305
    '''
    religion_marriage['total'] = religion_marriage.groupby('religion')['n'].transform('sum')
    religion_marriage['ratio'] = religion_marriage['n'] / religion_marriage['total']
    religion_marriage
    
    # 그래프 그리기
    plt.figure(figsize=(8, 5))
    ax=sns.barplot(data = religion_marriage, x = 'religion', y='ratio',
                 hue = 'marriage_type')
    
    plt.ylabel("이혼율 (%)")
    plt.xlabel("종교 유무")
    plt.title("종교 유무에 따른 이혼율 비교")
    plt.ylim(0, 1)
    
    for container in ax.containers:
        ax.bar_label(container, fmt="%.3f%%", fontsize=10)
    
    plt.show()

    📌 결과:


    🔹 7. 지역별 연령대 비율

    # 지역 변수
    dr={1:'서울',
       2:'수도권(인천/경기)',
       3:'부산/경남/울산',
       4:'대구/경북',
       5:'대전/충남',
       6:'강원/충북',
       7:'광주/전남/전북/제주도'}
    
    welfare['code_region'] = welfare['code_region'].replace(dr)
    
    # 연령대 변수 만들기
    welfare = welfare.assign(age = 2019-welfare['birth'] + 1)
    welfare['age'].describe()
    welfare = welfare.assign(ageg = np.where(welfare['age']<30, 'young', 
                                             np.where(welfare['age']<=59, 'middle', 'old')))
    
    region_ageg = welfare.groupby(['code_region', 'ageg'], as_index = False).agg(n = ('ageg', 'count'))
    region_ageg.head()
    '''
        code_region    ageg     n  total     ratio
    0         강원/충북  middle   351   1137  0.308707
    1         강원/충북     old   522   1137  0.459103
    2         강원/충북   young   264   1137  0.232190
    3  광주/전남/전북/제주도  middle   784   2466  0.317924
    4  광주/전남/전북/제주도     old  1108   2466  0.449311
    '''
    
    # 비율 계산
    region_ageg['total'] = region_ageg.groupby('code_region')['n'].transform('sum')
    region_ageg['ratio'] = region_ageg['n'] / region_ageg['total']
    
    # 그래프 그리기
    plt.figure(figsize=(8, 5))
    ax=sns.barplot(data = region_ageg, x = 'code_region', y='ratio',
                 hue = 'ageg')
    plt.xticks(rotation=25)
    plt.ylabel("연령대 비율 (%)")
    plt.xlabel("지역")
    plt.title("지역에 따른 연령대 비율 비교")
    plt.ylim(0, 0.6)
    
    for container in ax.containers:
        ax.bar_label(container, fmt="%.3f%%", fontsize=7)
    
    plt.show()

    📌 결과: 지역별로 연령대 분포가 다르게 나타났습니다.

    〰 비율 구하는 다른 방법(value_counts(normalize=True) 사용)

    region_ageg2 = welfare.groupby('code_region', as_index = False)['ageg'].value_counts(normalize=True)
    region_ageg2 = region_ageg2.assign(proportion = region_ageg2['proportion']*100).round(1)
    '''
         code_region    ageg  proportion
    0          강원/충북     old        45.9
    1          강원/충북  middle        30.9
    2          강원/충북   young        23.2
    3   광주/전남/전북/제주도     old        44.9
    4   광주/전남/전북/제주도  middle        31.8
    '''
    
    sns.barplot(data=region_ageg2,
                y='code_region', x='proportion',
                hue='ageg')
    
    plt.show()

    〰 누적 막대 그래프 만들기 (피벗 이용)

    # 시각화(막대, 누적)
    '''
         code_region    ageg  proportion
    0          강원/충북     old        45.9
    1          강원/충북  middle        30.9
    2          강원/충북   young        23.2
    3   광주/전남/전북/제주도     old        44.9
    4   광주/전남/전북/제주도  middle        31.8
    
    피벗을 이용해 이 구조를 바꿀거임.
    피벗: 행과 열을 회전하여 표의 구성을 변경하는 작업.
          누적 그래프 형태로 시각화 할 때 사용
    1. 지역, 연령대, 비율 추출
    2. DataFrame.pivot()
    2-1. 지역을 기준으로 : index = 지역
    2-2. 연령대별로 컬럼을 구성: columns = 연령대
    2-3. 각 항목의 값을 비율로 채우기: values = 비율
    '''
    
    pivot_df = region_ageg2[['code_region', 'ageg', 'proportion']].pivot(index='code_region', columns='ageg', values = 'proportion')
    
    # 초년 중년 노년 으로 순서 바꾸기
    reorder_df = pivot_df.sort_values('old')[['young', 'middle', 'old']]
    
    '''
    ageg          young  middle   old
    code_region                      
    수도권(인천/경기)     28.7    38.8  32.5
    서울             23.9    38.5  37.6
    대전/충남          25.0    33.6  41.3
    부산/경남/울산       22.9    33.4  43.8
    광주/전남/전북/제주도   23.3    31.8  44.9
    강원/충북          23.2    30.9  45.9
    대구/경북          20.0    29.6  50.4
    '''
    
    reorder_df.plot.barh(stacked = True)
    plt.show()


    🔹 마무리

    오늘은 한국복지패널데이터를 활용해 한국인의 삶을 분석해 보았습니다. 데이터 분석을 통해 성별, 연령, 직업, 종교 등의 요소가 개인의 경제 및 사회적 특성과 어떻게 연관되는지를 확인할 수 있었습니다. 😊

Designed by Tistory.