[패캠] 우리나라의 행복지수는 몇 위? 아니, 행복지수가 도대체 뭔데?

2023. 5. 17. 23:50Python/Kaggle

데이터 소개
    - 이번 주제는 World Happiness Report up to 2020을 사용합니다.
    
    - 각 파일의 칼럼은 아래와 같습니다.
    Country: 국가
    Region: 국가의 지역
    Happiness Rank: 행복지수 순위
    Happiness Score: 행복지수 점수
    GDP per capita: 1인당 GDP
    Healthy Life Expectancy: 건강 기대수명
    Social support: 사회적 지원
    Freedom to make life choices: 삶에 대한 선택의 자유
    Generosity: 관용
    Corruption Perception: 부정부패
    Dystopia + Residual: 그 외

데이터 출처: https://www.kaggle.com/mathurinache/world-happiness-report

최종 목표
    - 전문가에 의해 작성된 데이터 분석해 보기
    - 시간적으로 변하는 데이터의 Plot 방법 이해
    - 데이터 시각화를 통한 인사이트 습득 방법의 이해
    - 학습된 모델로부터의 인사이트 획득 방법 습득

 

Step 1. 데이터셋 준비하기

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import os
# os.environ을 이용하여 Kaggle API Username, Key 세팅하기
os.environ['KAGGLE_USERNAME'] = 'jhighllight'
os.environ['KAGGLE_KEY'] = 'xxxxxxxxxxxxxxxxxxxxxxx'
# Linux 명령어로 Kaggle API를 이용하여 데이터셋 다운로드하기 (!kaggle ~)
# Linux 명령어로 압축 해제하기
!rm *.*
!kaggle datasets download -d mathurinache/world-happiness-report
!unzip '*.zip'

rm: cannot remove '*.*': No such file or directory

Downloading world-happiness-report.zip to /content

  0% 0.00/67.4k [00:00 <?,? B/s]

100% 67.4k/67.4k [00:00 <00:00, 75.5MB/s]

Archive:  world-happiness-report.zip

  inflating: 2015.csv                

  inflating: 2016.csv                

  inflating: 2017.csv                

  inflating: 2018.csv                

  inflating: 2019.csv                

  inflating: 2020.csv                

  inflating: 2021.csv                

  inflating: 2022.csv               

 

Pandas 라이브러리로 csv파일 읽어 들이기

 

df = dict()
df['2015'] = pd.read_csv('/content/2015.csv')
df['2016'] = pd.read_csv('/content/2016.csv')
df['2017'] = pd.read_csv('/content/2017.csv')
df['2018'] = pd.read_csv('/content/2018.csv')
df['2019'] = pd.read_csv('/content/2019.csv')
df['2020'] = pd.read_csv('/content/2020.csv')
df['2015']

df['2020']

Step 2. 데이터프레임 구성하기

연도별 데이터 표준화하기

for key in df:
  print(key, df[key].columns) # 각 데이터프레임의 컬럼 확인

2015 Index(['Country', 'Region', 'Happiness Rank', 'Happiness Score',

       'Standard Error', 'Economy (GDP per Capita)', 'Family',

       'Health (Life Expectancy)', 'Freedom', 'Trust (Government Corruption)',

       'Generosity', 'Dystopia Residual'],

      dtype='object')

2016 Index(['Country', 'Region', 'Happiness Rank', 'Happiness Score',

       'Lower Confidence Interval', 'Upper Confidence Interval',

       'Economy (GDP per Capita)', 'Family', 'Health (Life Expectancy)',

       'Freedom', 'Trust (Government Corruption)', 'Generosity',

       'Dystopia Residual'],

      dtype='object')

2017 Index(['Country', 'Happiness.Rank', 'Happiness.Score', 'Whisker.high',

       'Whisker.low', 'Economy.. GDP.per.Capita.', 'Family',

       'Health..Life.Expectancy.', 'Freedom', 'Generosity',

       'Trust..Government.Corruption.', 'Dystopia.Residual'],

      dtype='object')

2018 Index(['Overall rank', 'Country or region', 'Score', 'GDP per capita',

       'Social support', 'Healthy life expectancy',

       'Freedom to make life choices', 'Generosity',

       'Perceptions of corruption'],

      dtype='object')

2019 Index(['Overall rank', 'Country or region', 'Score', 'GDP per capita',

       'Social support', 'Healthy life expectancy',

       'Freedom to make life choices', 'Generosity',

       'Perceptions of corruption'],

      dtype='object')

2020 Index(['Country name', 'Regional indicator', 'Ladder score',

       'Standard error of ladder score', 'upperwhisker', 'lowerwhisker',

       'Logged GDP per capita', 'Social support', 'Healthy life expectancy',

       'Freedom to make life choices', 'Generosity',

       'Perceptions of corruption', 'Ladder score in Dystopia',

       'Explained by: Log GDP per capita', 'Explained by: Social support',

       'Explained by: Healthy life expectancy',

       'Explained by: Freedom to make life choices',

       'Explained by: Generosity', 'Explained by: Perceptions of corruption',

       'Dystopia + residual'],

      dtype='object')

# 각 년도별로 다른 정보를 가진 데이터 프레임의 Column을 동일하게 표준화하기
cols = ['country', 'score', 'economy', 'family', 'health', 'freedom', 'trust', 'generosity', 'residual']
df['2015'].drop(['Region', 'Happiness Rank', 'Standard Error'], axis=1, inplace=True)   # generosity, trust 순서 반대
df['2016'].drop(['Region', 'Happiness Rank', 'Lower Confidence Interval', 
                 'Upper Confidence Interval'], axis=1, inplace=True)    # generosity, trust 순서 반대
df['2017'].drop(['Happiness.Rank', 'Whisker.high', 'Whisker.low'], axis=1, inplace=True)
df['2018'].drop(['Overall rank'], axis=1, inplace=True)  # residual 없음
df['2019'].drop(['Overall rank'], axis=1, inplace=True)  # residual 없음
df['2020'].drop(['Regional indicator','Standard error of ladder score', 'upperwhisker', 'lowerwhisker',
       'Logged GDP per capita', 'Social support', 'Healthy life expectancy',
       'Freedom to make life choices', 'Generosity',
       'Perceptions of corruption', 'Ladder score in Dystopia'], axis=1, inplace=True)
df['2018'].columns

Index(['Country or region', 'Score', 'GDP per capita', 'Social support',

       'Healthy life expectancy', 'Freedom to make life choices', 'Generosity',

       'Perceptions of corruption'],

      dtype='object')

df['2019'].columns

Index(['Country or region', 'Score', 'GDP per capita', 'Social support',

       'Healthy life expectancy', 'Freedom to make life choices', 'Generosity',

       'Perceptions of corruption'],

      dtype='object')

df['2018']['residual'] = df['2018']['Score'] - df['2018'][['GDP per capita', 'Social support', 
                                                           'Healthy life expectancy', 'Freedom to make life choices', 'Generosity', 
                                                           'Perceptions of corruption']].sum(axis=1)
df['2019']['residual'] = df['2019']['Score'] - df['2019'][['GDP per capita', 'Social support', 
                                                           'Healthy life expectancy', 'Freedom to make life choices', 'Generosity', 
                                                           'Perceptions of corruption']].sum(axis=1)
df['2016'].columns

Index(['Country', 'Happiness Score', 'Economy (GDP per Capita)', 'Family',

       'Health (Life Expectancy)', 'Freedom', 'Trust (Government Corruption)',

       'Generosity', 'Dystopia Residual'],

      dtype='object')

for col_name in df:
    df[col_name].columns = cols
df['2015']

# 아래 셀과 동일한 데이터프레임으로 결합하기
df_all = pd.concat(df, axis=0)
df_all.index.names = ['year', 'rank']
df_all

# 아래 셀과 동일한 데이터프레임으로 변형하기
df_all.reset_index(inplace=True)
df_all['rank'] += 1
df_all

Pivot을 이용하여 데이터프레임 재구성하기

# 아래 셀과 동일한 데이터프레임 구성하기
# Hint) DataFrame의 pivot() 메소드 활용
rank_table = df_all.pivot(index='country', columns=['year'], values='rank')
rank_table.sort_values('2020', inplace=True)
rank_table.head(20)

Step 3. 데이터 시각화 수행하기

# 아래 셀과 동일하게 년도별 순위 변화를 시각화하기
# Hint) plt.plot을 이용하고, 필요한 경우 데이터프레임을 변형하면서 그리시오.

fig = plt.figure(figsize=(10, 50))
rank2020 = rank_table['2020'].dropna()
for c in rank2020.index:
  t = rank_table.loc[c].dropna()
  plt.plot(t.index, t, '.-')

plt.xlim(['2015', '2020'])
plt.ylim([0, rank_table.max().max() + 1])
plt.yticks(rank2020, rank2020.index)
ax = plt.gca()
ax.invert_yaxis()
ax.yaxis.set_label_position('right')
ax.yaxis.tick_right()
plt.tight_layout()
plt.show()

분야별로 나누어 점수 시각화하기

# sns.barplot()을 이용하여 아래 셀과 동일하게 시각화하기
# Hint) 필요에 따라 데이터프레임을 수정하여 사용하시오. 적절한 수정을 위해 누적합(pd.cumsum())을 활용하시오.
df_all

fig = plt.figure(figsize=(6, 8))
data = df_all[df_all['year'] == '2020']
data = data.loc[data.index[:20]]

d = data[data.columns[4:]].cumsum(axis=1)
d = d[d.columns[::-1]]
d['country'] = data['country']

sns.set_color_codes('muted')
colors = ['r', 'g', 'b', 'c', 'm', 'y', 'purple'][::-1]
for idx, c in enumerate(d.columns[:-1]):
    sns.barplot(x=c, y='country', data=d, label=c, color=colors[idx])

plt.legend(loc='lower left')
plt.title('Top 20 Happiness Scores in Details')
plt.xlabel('Happiness Score')
sns.despine(left=True, bottom=True)

Column 간의 상관성 시각화하기

# 상관성 Heatmap, Pairplot 등으로 상관성을 시각화하기
sns.heatmap(df_all.drop('rank', axis=1).corr(), annot=True, cmap='YlOrRd')

sns.pairplot(df_all.drop('rank', axis=1))

Step 4. 모델 학습을 위한 데이터 전처리 

# 학습할 모델의 입출력을 정의하시오. Column의 의미를 고려하여 선정하시오.
col_input_list = ['economy', 'family', 'health', 'freedom', 'generosity', 'trust']
col_out = 'score'
# 2015년 ~ 2019년도 데이터를 학습 데이터로, 2020년도 데이터를 테스트 데이터로 분리하기
df_train = df_all[df_all['year'] != '2020']
df_test = df_all[df_all['year'] == '2020']

X_train = df_train[col_input_list]
y_train = df_train[col_out]
X_test = df_test[col_input_list]
y_test = df_test[col_out]

StandardScaler를 이용해 학습 데이터 표준화하기

from sklearn.preprocessing import StandardScaler
# StandardScaler를 이용해 학습 데이터를 표준화하기
scaler = StandardScaler()
scaler.fit(X_train)

X_norm = scaler.transform(X_train)
X_train = pd.DataFrame(X_norm, index=X_train.index, columns=X_train.columns)

X_norm = scaler.transform(X_test)
X_test = pd.DataFrame(X_norm,index=X_test.index, columns=X_test.columns)

Step 5. Regression 모델 학습하기

from sklearn.linear_model import LinearRegression
X_train.fillna(0, inplace=True)
# LinearRegression 모델 생성/학습
model_lr = LinearRegression()
model_lr.fit(X_train, y_train)

모델 학습 결과 평가하기

from sklearn.metrics import mean_absolute_error, mean_squared_error
from math import sqrt
# Predict를 수행하고 mean_absolute_error, rmse 결과 출력하기
pred = model_lr.predict(X_test)
print(mean_absolute_error(y_test, pred))
print(sqrt(mean_squared_error(y_test, pred)))

0.44158604379489913

0.5668203591972287

 

XGBoost Regression 모델 학습하기

from xgboost import XGBRegressor
# XGBRegressor 모델 생성/학습
model_xgb = XGBRegressor()
model_xgb.fit(X_train, y_train)

# Predict를 수행하고 mean_absolute_error, rmse 결과 출력하기
pred = model_xgb.predict(X_test)
print(mean_absolute_error(y_test, pred))
print(sqrt(mean_squared_error(y_test, pred)))

0.4077824096522352

0.5170796927878635

 

Step 6. 모델 학습 결과 심화 분석하기

실제 값과 추측 값의 Scatter plot 시각화하기

# y_test vs. pred Scatter 플랏으로 시각적으로 분석하기
plt.scatter(x=y_test, y=pred)
plt.plot([0, 9], [0, 9], 'r-')
plt.show()

LinearRegression 모델의 Coefficient 시각화하기

# model_lr.coef_ 시각화하기
plt.bar(X_train.columns, model_lr.coef_)

XGBoost 모델의 Feature Importance 시각화하기

# model_xgb.feature_importance_ 시각화하기
plt.bar(X_train.columns, model_xgb.feature_importances_)