파이썬으로 구현하는 인구 피라미드 그래프: 2023년 연령별 사망자 수 데이터 분석

인구 피라미드 그래프 형식의 남녀 연령별 사망주 수 이미지
( 인구 피라미드 그래프 형식의 남녀 연령별 사망자 수 이미지)

인구 통계 데이터를 시각화할 때 데이터 레이블을 추가하면 정보의 정확성과 가독성이 크게 향상됩니다. 오늘은 인구 피라미드 그래프에 데이터 레이블을 포함하여 2023년 연령별 사망자 수를 시각화하는 방법을 알아보겠습니다.

데이터 개요

위 파이썬 시각화 그래프의 기초 데이터는 ’24년 2월에 통계청에서 발표한 2023년 출생·사망통계(잠정)에 근거하고 있습니다. 해당 데이터를 표형태로 정리해보면 아래와 같습니다. 사망자 수 단위는 천명입니다.

연령 그룹남성 사망자 수여성 사망자 수
90+15.342.1
80-8963.569.6
70-7945.524.6
60-6934.313.2
50-5918.07.2
40-497.03.8
30-392.81.5
20-291.70.9
10-190.40.4
1-90.20.1
0-0.30.3

남녀 연령별 사망자 수 기반 인구 피라미드 그래프 이미지
(통계층 자료에서 발췌한 인구 피라미드 그래프 이미지 )

위 테이블에서 나타난 2023년 연령별 사망자 수 데이터를 인구 피라미드 그래프로 표현하면서, 각 연령대별 정확한 수치를 데이터 레이블로 표시하여 더욱 상세한 정보를 제공하겠습니다.

파이썬 시각화 코드 구현

import numpy as np
import matplotlib.pyplot as plt

# 데이터 준비
age_groups = ['90+', '80-89', '70-79', '60-69', '50-59', '40-49', 
              '30-39', '20-29', '10-19', '1-9', '0-']
male_deaths = [15.3, 63.5, 45.5, 34.3, 18.0, 7.0, 2.8, 1.7, 0.4, 0.2, 0.3]
female_deaths = [42.1, 69.6, 24.6, 13.2, 7.2, 3.8, 1.5, 0.9, 0.4, 0.1, 0.3]

# GridSpec을 사용하여 그림 생성
fig = plt.figure(figsize=(15, 8))
gs = fig.add_gridspec(1, 3, width_ratios=[4, 0.01, 4])  # 중앙 열의 비율을 0.01로 설정

# 세 개의 서브플롯 생성
ax_left = fig.add_subplot(gs[0])
ax_center = fig.add_subplot(gs[1])
ax_right = fig.add_subplot(gs[2])

y_pos = np.arange(len(age_groups))

# 왼쪽 플롯 (남성)
male_bars = ax_left.barh(y_pos, -np.array(male_deaths), align='center', 
                        color='#5AB1EF', height=0.7)

# 오른쪽 플롯 (여성)
female_bars = ax_right.barh(y_pos, female_deaths, align='center',
                           color='#FFB848', height=0.7)

# 데이터 레이블 추가
def add_labels(ax, bars):
    for bar in bars:
        width = bar.get_width()
        x = width
        value = abs(width)
        ax.text(x, bar.get_y() + bar.get_height()/2, f'{value}',
                ha='right' if width < 0 else 'left',
                va='center',
                fontsize=9,
                fontweight='bold',
                color='black',
                bbox=dict(pad=0.4, facecolor='none', edgecolor='none'))

add_labels(ax_left, male_bars)
add_labels(ax_right, female_bars)

# 중앙 플롯 (연령 그룹)
ax_center.set_yticks(y_pos)
ax_center.tick_params(axis='y', length=0)
# 연령 레이블 가운데 정렬
ax_center.set_yticklabels(age_groups, ha='center')

# 중앙 열의 스타일 설정
ax_center.set_xlim(-0.5, 0.5)  # x축 범위를 줄여서 레이블이 더 가운데에 오도록 조정
ax_center.set_xticks([])
for spine in ax_center.spines.values():
    spine.set_visible(False)

# 왼쪽과 오른쪽 플롯의 스타일 설정
for ax in [ax_left, ax_right]:
    ax.grid(axis='x', linestyle='-', alpha=0.1)
    ax.set_yticks([])
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    
# x축 범위 설정
max_value = max(max(male_deaths), max(female_deaths))
ax_left.set_xlim(-max_value*1.1, 0)
ax_right.set_xlim(0, max_value*1.1)

# 축 레이블 추가
ax_left.set_xlabel('Number of Deaths (thousands)', ha='right')
ax_right.set_xlabel('Number of Deaths (thousands)', ha='left')

# 남성/여성 레이블 추가
ax_left.text(-max_value/2, len(age_groups), 'Male', ha='center', va='bottom', fontsize=12)
ax_right.text(max_value/2, len(age_groups), 'Female', ha='center', va='bottom', fontsize=12)

# x축 눈금 포맷 설정
def format_ticks(x, p):
    return f'{abs(x)}'
ax_left.xaxis.set_major_formatter(plt.FuncFormatter(format_ticks))
ax_right.xaxis.set_major_formatter(plt.FuncFormatter(format_ticks))

# 그래프 제목 추가
fig.suptitle('Age-Specific Mortality by Gender', y=0.95, fontsize=14)

plt.tight_layout()
plt.subplots_adjust(top=0.9)  # 제목을 위한 여백 조정
plt.show()

심층 데이터 분석 인사이트

1. 연령대별 사망률 격차

    • 80-89세 구간: 남성(63.5천 명), 여성(69.6천 명)으로 최고점
    • 70대 이하에서는 전반적으로 남성 사망률이 높음
    • 연령 증가에 따른 성별 격차 패턴 변화 관찰

    2. 생애주기별 특징

      • 영유아기(0세): 남녀 동일한 사망률(0.3천 명)
      • 청장년층(20-49세): 남성 사망률이 여성의 약 2배
      • 노년층(80세 이상): 여성 사망률 급증

      3. 정책적 시사점

        • 성별·연령별 맞춤형 보건의료 정책 필요성
        • 고령층 여성 대상 의료서비스 확충 요구
        • 중년 남성 사망률 감소를 위한 예방의료 강화

        마무리

        데이터 레이블이 포함된 인구 피라미드 그래프는 연령별 사망자 수의 정확한 수치를 직관적으로 파악할 수 있게 해줍니다. 이러한 시각화는 인구통계 분석과 보건의료 정책 수립에 중요한 기초자료로 활용될 수 있습니다. 코드 상세 해설은 아래의 내용을 참고해주세요.

        혹시, 사망자 수와 대척점에 있는 개념인 합계출산율에 대한 정보를 알고 싶으신 분은 합계출산율 뜻과 계산법: R로 트렌디한 시각화까지 포스트를 참고해 보시기 바랍니다.

        # 코드 상세해설

        1. 필요한 라이브러리 임포트
        import numpy as np
        import matplotlib.pyplot as plt
        • numpy: 수치 계산을 위한 라이브러리
        • matplotlib.pyplot: 그래프 생성을 위한 라이브러리
        2. 데이터 준비
        age_groups = ['90+', '80-89', '70-79', '60-69', '50-59', '40-49', 
                      '30-39', '20-29', '10-19', '1-9', '0-']
        male_deaths = [15.3, 63.5, 45.5, 34.3, 18.0, 7.0, 2.8, 1.7, 0.4, 0.2, 0.3]
        female_deaths = [42.1, 69.6, 24.6, 13.2, 7.2, 3.8, 1.5, 0.9, 0.4, 0.1, 0.3]

        연령 그룹과 각 성별의 사망자 수 데이터를 리스트로 정의합니다.

        3. 그래프 구조 설정
        fig = plt.figure(figsize=(15, 8))
        gs = fig.add_gridspec(1, 3, width_ratios=[4, 0.01, 4])
        • figsize=(15, 8): 그래프의 전체 크기를 설정 (가로 15, 세로 8)
        • add_gridspec: 그래프를 3개의 열로 나눔. 비율은 [4, 0.01, 4]로 설정하여 중앙 열을 매우 좁게 만듦
        4. 서브플롯 생성
        ax_left = fig.add_subplot(gs[0])
        ax_center = fig.add_subplot(gs[1])
        ax_right = fig.add_subplot(gs[2])

        3개의 서브플롯(왼쪽, 중앙, 오른쪽)을 생성합니다.

        5. 막대 그래프 그리기
        y_pos = np.arange(len(age_groups))
        
        male_bars = ax_left.barh(y_pos, -np.array(male_deaths), align='center', 
                                color='#5AB1EF', height=0.7)
        female_bars = ax_right.barh(y_pos, female_deaths, align='center',
                                   color='#FFB848', height=0.7)
        • barh: 수평 막대 그래프를 그리는 함수
        • 남성 데이터는 음수로 변환하여 왼쪽에 표시
        • 여성 데이터는 오른쪽에 표시
        6. 데이터 레이블 추가
        def add_labels(ax, bars):
            for bar in bars:
                width = bar.get_width()
                x = width
                value = abs(width)
                ax.text(x, bar.get_y() + bar.get_height()/2, f'{value}',
                        ha='right' if width < 0 else 'left',
                        va='center',
                        fontsize=9,
                        fontweight='bold',
                        color='black',
                        bbox=dict(pad=0.4, facecolor='none', edgecolor='none'))
        
        add_labels(ax_left, male_bars)
        add_labels(ax_right, female_bars)

        각 막대에 해당하는 수치를 레이블로 추가합니다.

        7. 중앙 열 스타일 설정
        ax_center.set_yticks(y_pos)
        ax_center.tick_params(axis='y', length=0)
        ax_center.set_yticklabels(age_groups, ha='center')
        ax_center.set_xlim(-0.5, 0.5)
        ax_center.set_xticks([])
        for spine in ax_center.spines.values():
            spine.set_visible(False)

        중앙 열에 연령 그룹 레이블을 표시하고, 불필요한 축과 테두리를 제거합니다.

        8. 왼쪽과 오른쪽 플롯의 스타일 설정
        for ax in [ax_left, ax_right]:
            ax.grid(axis='x', linestyle='-', alpha=0.1)
            ax.set_yticks([])
            ax.spines['top'].set_visible(False)
            ax.spines['right'].set_visible(False)

        왼쪽과 오른쪽 플롯에 격자를 추가하고, 불필요한 축을 제거합니다.

        9. x축 범위 설정 및 레이블 추가
        max_value = max(max(male_deaths), max(female_deaths))
        ax_left.set_xlim(-max_value*1.1, 0)
        ax_right.set_xlim(0, max_value*1.1)
        
        ax_left.set_xlabel('Number of Deaths (thousands)', ha='right')
        ax_right.set_xlabel('Number of Deaths (thousands)', ha='left')
        
        ax_left.text(-max_value/2, len(age_groups), 'Male', ha='center', va='bottom', fontsize=12)
        ax_right.text(max_value/2, len(age_groups), 'Female', ha='center', va='bottom', fontsize=12)

        x축의 범위를 설정하고, 축 레이블과 성별 레이블을 추가합니다.

        10. x축 눈금 포맷 설정
        def format_ticks(x, p):
            return f'{abs(x)}'
        ax_left.xaxis.set_major_formatter(plt.FuncFormatter(format_ticks))
        ax_right.xaxis.set_major_formatter(plt.FuncFormatter(format_ticks))

        x축 눈금의 값을 절대값으로 표시합니다.

        11. 그래프 마무리
        fig.suptitle('Age-Specific Mortality by Gender', y=0.95, fontsize=14)
        plt.tight_layout()
        plt.subplots_adjust(top=0.9)
        plt.show()

        그래프에 제목을 추가하고, 레이아웃을 조정한 후 그래프를 표시합니다.

        유사한 게시물