수업(국비지원)/Python

[Python] 지도학습 예제 - titanic

byeolsub 2023. 4. 27. 12:46
'''
2022-12-16 복습
  sklearn 모듈을 이용한 머신러닝
  지도 학습 : 기계학습시 정답을 제시.
     회귀분석 : 과거의 데이터를 회귀선을 이용하여 분석
               독립변수(설명변수) : 종속변수에 영향을 미침
               종속변수(예측변수) : 예측해야할 데이터
        
        단순회귀분석 : 독립변수 1개, 종속변수 1개
             단항 회귀분석 : 직선의 방정식
             다항 회귀분석 : 곡선의 방정식
       
        다중회귀분석 : 독립변수 여러개, 종속변수 1개

     알고리즘 : 선형회귀분석(LinearRegression)
     평가 방식 : RMSE : mse(평균제곱오차)의 제곱근
                   mse : (실제 데이터 - 예측데이터)**2의 평균
                          작은 값일 수록 정확도가 높아짐
 분류(Classification) : 설명변수를 이용하여 목표변수의 값을 예측
     알고리즘 : KNN(K-Nearset-Nerghbors) : 최근접이웃알고리즘 
'''

 📌

'''
    titanic 속성
pclass : Passenger Class, 승객 등급
survived : 생존 여부
name : 승객 이름
sex : 승객 성별
age : 승객 나이
sibsp : 탑승 한 형제/배우자 수
parch : 탑승 한 부모/자녀 수
ticket : 티켓 번호
fare : 승객 지불 요금
cabin : 선실 이름
embarked : 승선항 (C = 쉘 부르그, Q = 퀸즈타운, S = 사우스 햄튼)
body : 사망자 확인 번호
home.dest : 고향/목적지
'''

import pandas as pd
df_train = pd.read_csv("data/titanic_train.csv")
df_test = pd.read_csv("data/titanic_test.csv")
df_train.info()
df_test.info()

# df_train 데이터에서 생존여부를 그래프로 출력하기
df_train["survived"].value_counts()
df_train["survived"].value_counts().plot.bar()
df_train["survived"].value_counts().plot(kind="bar")

# 좌석 등급별 생존여부 조회하기
df_train.groupby("pclass")["survived"].value_counts()
df_train[["pclass","survived"]].value_counts()

# index로 정렬
df_train.groupby("pclass")["survived"].value_counts().sort_index()
df_train[["pclass","survived"]].value_counts().sort_index()

# 그래프로 출력
#1
df_train.groupby("pclass")["survived"]\\
    .value_counts().sort_index().plot(kind="bar")

#2
# df_train 데이터에서 pclass별 건수를 그래프로 출력
# hue="survived" : 건수를 survived 컬럼의 값으로 분리하여
# x 축의 값은 plcass 지만 y축의 값은 무조건 건수.
import seaborn as sns
sns.countplot(x="pclass", hue="survived", data=df_train)

# 1. age 컬럼의 결측값을 df_train 데이터의 평균값으로 변경하기(df_train, df_test)

age_mean = df_train["age"].mean()
age_mean

df_train["age"] = df_train["age"].fillna(age_mean)
df_test["age"] = df_test["age"].fillna(age_mean)

df_train.info()
df_test.info()

# embarked 컬럼의 결측값을 최빈값으로 변경
embarked_freq = df_train["embarked"].value_counts().idxmax()
embarked_freq

df_train["embarked"] = df_train["embarked"].fillna(embarked_freq)
df_train.info()

# 3. name, ticket, cabin, body, home.dest 컬럼 제거하기(df_train, df_test)
df_train = df_train.drop(["name","ticket","cabin","body","home.dest"], axis=1)
df_test = df_test.drop(["name","ticket","cabin","body","home.dest"], axis=1)

# 4. df_trai, df_test 데이터를 통합데이터로 생성하기 
# (계속 두번씩 하니까 합쳐서 한번에 하기 위하여)
whole_df = df_train.append(df_test)
whole_df.info()

# 훈련데이터의 갯수 저장하기 => 훈련데이터/ 테스트데이터 분리하기 위하여 
train_num = len(df_train)
train_num

# 원핫인코딩하기
whole_df_encoded = pd.get_dummies(whole_df)
whole_df_encoded.info()

# 5. 설명변수, 목표변수 분리
df_train = whole_df_encoded[:train_num]
df_train

df_test = whole_df_encoded[train_num:]
df_test

#훈련 설명 변수
x_train = df_train.loc\\
    [:, df_train.columns != "survived"].values
x_train # 2차원 배열의 형태. 
x_train.shape # (916, 10)

# 훈련 목표변수
y_train = df_train["survived"].values

# 테스트 설명변수
x_test = df_test.loc\\
    [:, df_test.columns != "survived"].values
x_test # 2차원 배열의 형태
x_test.shape # (393, 7)
    
# 테스트 목표변수
y_test = df_test["survived"].values

 


 📌

# 로지스틱 회귀분석 모델을 이용하여 분류하기
# 선형회귀분석은 직선이나 곡선이나 상향그래프가 없음
# 로지스틱 회귀분석은 직선을 로그함수로 바꿔서 0 ~ 1사이의 값을 넘겨준다.
# 선형데이터를 로지스틱 함수로 바꾸어서 모든 수를 0~1로 변형
# 로지스틱 회귀분석 분류 알고리즘 (그래서 분류로 구분된다.)
# 0.5 미만:0, 0.5 이상 :1

from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(random_state=0)
lr.fit(x_train, y_train)
y_pred = lr.predict(x_test)
y_pred[:10]
y_test[:10]

# 분류모델 평가
# 1. 혼동행렬
from sklearn.metrics import confusion_matrix
con_mat = confusion_matrix(y_test,y_pred)
con_mat

# 2. 정확도, 정밀도, 재현율, f1score 출력
from sklearn.metrics import accuracy_score,\\
    recall_score,precision_score,f1_score
print("정확도:", accuracy_score(y_test, y_pred))
print("정밀도:", precision_score(y_test, y_pred)) 
print("재현율:",recall_score(y_test, y_pred))
print("F1-score:",f1_score(y_test, y_pred))

# cabin(선실) 컬럼을 추가하여 예측하기
#    : 결측값이 엄청 많다.
import pandas as pd
df_train = pd.read_csv("data/titanic_train.csv")
df_test = pd.read_csv("data/titanic_test.csv")
df_train.info()
df_test.info()

# 1. age 컬럼의 결측값을 df_train 데이터의 평균값으로 변경하기(df_train, df_test)
age_mean = df_train["age"].mean()
age_mean
df_train["age"] = df_train["age"].fillna(age_mean)
df_test["age"] = df_test["age"].fillna(age_mean)
df_train.info()
df_test.info()

# 2. embarked 컬럼의 결측값을 최빈값으로 변경
embarked_freq = df_train["embarked"].value_counts().idxmax()
embarked_freq
df_train["embarked"] = df_train["embarked"].fillna(embarked_freq)
df_train.info()

# 3. df_train, df_test를 whole_df 데이터 합하기
whole_df = df_train.append(df_test)
train_num = len(df_train)
whole_df.info()
# 데이터 전처리 하기
whole_df["cabin"].unique()
'''
E36 => E 
B96 B96 => B

cabin 컬럼의 첫번째 문자만 추출하여 cabin컬럼에 저장
'''
whole_df["cabin"] = whole_df["cabin"].str[0]
whole_df["cabin"].unique()

# cabin 컬럼의 결측값을 X로 치환하기
whole_df["cabin"] = whole_df["cabin"].fillna("X")

whole_df["cabin"].value_counts()

# cabin별 생존자별 건수 그래프
sns.countplot(x="cabin", hue="survived", data=whole_df)

# name 피처 활용
whole_df["name"].head()

# name의 ,를 기준으로 두번째 문자열이 당시의 사회적 지위에 해당하는 문자.
# name_grade 컬럼에 저장하기
name_grade = whole_df["name"].apply\\
    (lambda x:x.split(",")[1].split(".")[0])

name_grade.unique()
name_grade.value_counts()

# 호칭에 따라 , 사회적 지위를 나타냄. 
# 비슷한 지위로 표시
grade_dict = {
    "A":["Rev","Col","Major","Dr","Capt","Sir"], # 명예직
    "B":["Ms","Mme","Mrs","Dona"], # 여성
    "C":["Jonkheer","the Countess"], # 귀족
    "D":["Mr","Don"], # 남성
    "E":["Master"], # 젋은 남성
    "F":["Miss","Mile","Lady"] # 젊은 여성
    }

def give_grade(g) :
    for k,v in grade_dict.items() :
        for title in v :
            if g == title :
                return k
    return 'G'
name_grade = list(name_grade.map(lambda x : give_grade(x)))        
name_grade[:10]

name_grade.unique()
name_grade.value_counts()

# name별로 생존여부를 그래프로 출력하기
sns.countplot(x="name", hue="survived", data=whole_df)

# ticket, body, home.dest 컬럼 삭제
whole_df = whole_df.drop\\
    (["ticket","body","home.dest"], axis=1)
whole_df.info()

# whole_df 데이터를 one_hot 인코딩 하기
whole_df_encoded = pd.get_dummies(whole_df)
whole_df_encoded.info()

# x_train, x_test, y_train, y_test 데이터 분리
df_train = whole_df_encoded[:train_num]
df_test = whole_df_encoded[train_num:]    

x_train = \\
    df_train.loc[:, df_train.columns != 'survived'].values
y_train = df_train["survived"].values
x_test = \\
    df_test.loc[:,df_test.columns != 'survived'].values
y_test = df_test["survived"].values

####
from sklearn.linear_model import LogisticRegression
# random_state=0 : 설명변수들 사이에 가중치를 줄 수 있다.
#                  임의로 선택.
#                  모델의 재현을 위한 설정.
lr = LogisticRegression(random_state=0)
lr.fit(x_train, y_train)
y_pred = lr.predict(x_test)
y_pred[:10]
y_test[:10]

# 분류모델 평가
# 1. 혼동행렬
from sklearn.metrics import confusion_matrix
con_mat = confusion_matrix(y_test,y_pred)
con_mat

# 2. 정확도, 정밀도, 재현율, f1score 출력
from sklearn.metrics import accuracy_score,\\
    recall_score,precision_score,f1_score
print("정확도:", accuracy_score(y_test, y_pred))
print("정밀도:", precision_score(y_test, y_pred)) 
print("재현율:",recall_score(y_test, y_pred))
print("F1-score:",f1_score(y_test, y_pred))

# 피처별 영향력을 그래프로 출력하기
import numpy as np
import matplotlib.pyplot as plt
cols = df_train.columns.tolist()
cols.remove("survived")
x_pos = np.arange(len(cols))
plt.rcParams["figure.figsize"] = [5,4]
fig,ax = plt.subplots()
ax.barh(x_pos,lr.coef_[0],align="center",color="green",ecolor="black")
ax.set_yticks(x_pos)
ax.set_yticks(x_pos)
ax.set_yticklabels(cols)
ax.invert_yaxis()
ax.set_xlabel("coef")
ax.set_title("Each Feature's Coef")
plt.show()