👨‍💼

2.7 타이타닉 SAS - 2

 
SAS 9.4를 사용하여 머신러닝 모델을 적용한 분석을 진행해본다.
 

1. 추가 데이터 전처리

이제 환경을 약간 바꿔 SAS 9.4에서 작업을 해보도록 하겠습니다. 새로운 환경에서 실행했으니 복습하는 차원에서 데이터를 읽어 오는 것부터 다시 해보도록 하겠습니다.

1) 데이터 읽어오기

1-1 라이브러리 지정

타이타닉 데이터가 있는 폴더를 찾아 폴더의 주소를 입력하고 Libname을 사용하여 라이브러리 지정을 합니다. 지정을 하게 되면 다음과 같이 Titan 라이브러리가 생기게 됩니다.
libname titan "C:\Users\help\Downloads\titanic";
 
notion imagenotion image

1-2 데이터 가져오기

Train 데이터
앞서 배운 PROC IMPORT를 사용하여 CSV파일로 되어있는 데이터셋을 불러옵시다. 실행 후 Titan 라이브러리 안에 Train SAS 파일이 생성된것을 확인할 수 있습니다.
PROC IMPORT DATAFILE = "C:\Users\help\Downloads\titanic\TRAIN.CSV" DBMS = CSV OUT = TITAN.TRAIN REPLACE; RUN;
 
Test 데이터
테스트 데이터도 동일하게 불러옵시다. 실행 후 Test SAS 파일이 생성된것을 확인 할 수 있습니다.
PROC IMPORT DATAFILE = "C:\Users\help\Downloads\titanic\TEST.CSV" DBMS = CSV OUT = TITAN.TEST REPLACE; RUN;
 

2) 데이터 전처리

2-1 Name

앞서 파이썬에서 전처리 한 내용을 SAS에서도 전처리 해보도록 하겠습니다. 다음과 같이 IF 문을 활용하여 New_Name이라는 새로운 변수를 생성할 수 있습니다. SAS에서 Index 함수는 찾고싶은 값의 위치를 찾아주는 역할을 하고, 문자에서 찾고 싶은 값이 있는지 없는지 조건을 나타내 주는 역할을 합니다.
그래서 INDEX(NANE, 'Mr.') 는 NAME이라는 변수에 문자형인 Mr.를 가지고 있으면 그 위치를 숫자로 표시해주고 그 숫자는 0보다 크기 때문에 다음과 같이 사용하면 됩니다.
Mr는 1, Mrs는 2, Miss는 3, Master는 4, 그외는 5로 정의했습니다.
DATA TITAN.TRAIN_NAME; SET TITAN.TRAIN; IF INDEX(NAME,'Mr.') > 0 THEN New_NAME = '1'; ELSE IF INDEX(NAME,'Mrs.') > 0 THEN New_NAME = '2'; ELSE IF INDEX(NAME,'Miss.') > 0 THEN New_NAME = '3'; ELSE IF INDEX(NAME,'Master.') THEN New_NAME = '4'; ELSE New_NAME = '5'; RUN;
 

2-2 Age

Age의 결측치를 제거하기 위해 평균값으로 결측치를 채우도록 하겠습니다. 평균값은 약 29.6으로 반올림하여 30세로 채워넣도록 하겠습니다.
그리고 Age를 연령대로 변경해서 분석해보도록 하겠습니다. 연령대는 앞서 배운 Proc Means를 활용해볼텐데요. 25백분위수가 20, 50백분위수가 28, 75백분위수가 38으로 확인해볼 수 있습니다. 이 값들을 새로운 변수를 만들때 적용해봅시다.
/*평균값 구하기 연령 평균 29.6 -> 약 30*/ PROC MEANS DATA=TITAN.TRAIN; VAR AGE; RUN;
DATA TITAN.TRAIN_AGE_1; SET TITAN.TRAIN_NAME; IF AGE = '.' THEN New_AGE = 30; ELSE New_AGE = AGE; RUN;
notion imagenotion image
DATA TITAN.TRAIN_AGE_2; SET TITAN.TRAIN_AGE_1; IF NEW_AGE < 20 THEN New_AGE_GROUP = 1; ELSE IF 20 <= NEW_AGE < 28 THEN New_AGE_GROUP = 2; ELSE IF 28 <= NEW_AGE < 38 THEN New_AGE_GROUP = 3; ELSE IF 38 <= NEW_AGE THEN New_AGE_GROUP = 4; RUN;
 

2-3 Fare

Fare는 구간을 임의로 나눠서 연속형 변수를 범주형 변수로 변경합니다. 이번 분석에서는 8달러, 8~12달러, 12달러 ~ 30달러, 30달러 이상으로 구간을 나누어 구간을 설정해보았습니다.
실제 타이타닉 첫 항해때 오른 승객들은 이민자부터 매우 부유한 귀족까지 다양했으며, 그에 따른 객실 가격은 당시 가격으로 1등실 30파운드 이상(스위트룸 870파운드), 2등실 12파운드, 3등실 3~8파운드라고 합니다.
DATA TITAN.TRAIN_Fare; SET TITAN.TRAIN_AGE_2; IF Fare < 8 THEN New_Fare_GROUP = 1; ELSE IF 8 <= Fare < 12 THEN New_Fare_GROUP = 2; ELSE IF 12 <= Fare < 30 THEN New_Fare_GROUP = 3; ELSE IF 30 <= Fare THEN New_Fare_GROUP = 4; RUN;
 

2-4 Family

Family는 Slbsp(함께 탑승한 형제 또는 배우자수)와 Parch(함께 탑승한 부모 또는 자녀의 수)와 자기자신을 포함하여 New_Family라는 새로운 변수를 생성합니다. 타이타닉호는 남자와 여자가 각각 배 앞머리와 뒷머리에 따로 떨어져 승선했는데, 가족단위는 같이 승선할 수 있었다고 합니다. 이에 따른 생존률의 변화를 파악해봅시다.
DATA TITAN.TRAIN_Family; SET TITAN.TRAIN_Fare; New_Family = SibSp + Parch + 1; RUN;
 

2-5 Embarked

Embark는 앞서 분석한것과 동일하게 결측치를 최빈값인 'S'로 대체합니다.
DATA TITAN.TRAIN_Embarked; SET TITAN.TRAIN_Family; IF Embarked = '' then Embarked = 'S'; RUN;
 

2-6 기타 변수 처리

Embarked/Sex는 문자형을 되어있는 것을 숫자형으로 변경하고, PClass는 이름을 New_Pclass로 변경합시다.
DATA TITAN.TRAIN_Other; SET TITAN.TRAIN_Embarked; IF Embarked = 'S' then New_Embarked = 1; ELSE IF Embarked = 'C' then New_Embarked = 2; ELSE IF Embarked = 'Q' then New_Embarked = 3; IF SEX = 'male' THEN New_Sex = 1; ELSE New_Sex = 2; New_Pclass = Pclass; RUN;
 

2-7 분석 데이터 / 테스트 데이터 확인

불필요한 변수 제거
이번 분석에서 사용하지 않은 Ticket Cabin PassingerId는 제거합니다.
DATA TITAN.NEW_TRAIN; SET TITAN.TRAIN_Other; DROP Ticket Cabin PassingerId; RUN;
 
테스트 데이터 처리
테스트 데이터도 동일하게 처리합니다. 지금까지 했던 작업을 그대로 돌려야하는데요. 코드는 위의 방식과 동일하고 코드는 하단에 있습니다.
 
/Test Data도 동일하게 적용*/ .* 1. Name */ DATA TITAN.Test_NAME; SET TITAN.Test; IF INDEX(NAME,'Mr.') > 0 THEN New_NAME = 1; ELSE IF INDEX(NAME,'Mrs.') > 0 or INDEX(NAME,'Mme.') > 0 THEN New_NAME = 2; ELSE IF INDEX(NAME,'Miss.') > 0 or INDEX(NAME,'Mlle.') > 0 or INDEX(NAME,'Ms.') > 0 THEN New_NAME = 3; ELSE IF INDEX(NAME,'Master.') THEN New_NAME = 4; ELSE New_NAME = 5; RUN; /* 2. Age */ /*평균값 구하기 연령 평균 29.6 -> 약 30*/ PROC MEANS DATA=TITAN.Test; VAR AGE; RUN; DATA TITAN.Test_AGE_1; SET TITAN.Test_NAME; IF AGE = '.' THEN New_AGE = 30; ELSE New_AGE = AGE; RUN; DATA TITAN.Test_AGE_2; SET TITAN.Test_AGE_1; IF NEW_AGE < 20 THEN New_AGE_GROUP = 1; ELSE IF 20 <= NEW_AGE < 28 THEN New_AGE_GROUP = 2; ELSE IF 28 <= NEW_AGE < 38 THEN New_AGE_GROUP = 3; ELSE IF 38 <= NEW_AGE THEN New_AGE_GROUP = 4; RUN; /* 3 Fare */ DATA TITAN.Test_Fare; SET TITAN.Test_AGE_2; IF Fare < 8 THEN New_Fare_GROUP = 1; ELSE IF 8 <= Fare < 12 THEN New_Fare_GROUP = 2; ELSE IF 12 <= Fare < 30 THEN New_Fare_GROUP = 3; ELSE IF 30 <= Fare THEN New_Fare_GROUP = 4; RUN; /* 4. Family */ DATA TITAN.Test_Family; SET TITAN.Test_Fare; New_Family = SibSp + Parch + 1; RUN; /* 5. Embarked*/ DATA TITAN.Test_Embarked; SET TITAN.Test_Family; IF Embarked = '' then Embarked = 'S'; RUN; /* 6. 기타변수 처리 */ /* Sex, Embarked Pclass*/ DATA TITAN.Test_Other; SET TITAN.Test_Embarked; IF Embarked = 'S' then New_Embarked = 1; ELSE IF Embarked = 'C' then New_Embarked = 2; ELSE IF Embarked = 'Q' then New_Embarked = 3; IF SEX = 'male' THEN New_Sex = 1; ELSE New_Sex = 2; New_Pclass = Pclass; RUN; /*6. 불필요한 변수 제외 */ DATA TITAN.NEW_Test; SET TITAN.Test_Other; DROP Ticket Cabin PassingerId; RUN;
 

2. Modeling

이제 모델을 만들 준비가 다 끝났습니다. 이제 다양한 모델을 만들어보고 Kaggle에 제출해 결과도 확인해 보도록 하겠습니다.

1) Decision Tree

Decision Tree 모델을 이용하여 분석을 해봅시다. 로지스틱 모델을 만드는 코드는 다음과 같습니다. Proc hpsplit를 이용합니다. Data에는 분석 데이터 이름을 넣고, Seed는 123으로 지정했습니다. Class에는 범주형 변수들을 넣고, Model에는 타겟변수 = 변수1, 변수2 ... 변수n 형식으로 작성합니다. code file은 scoring에 필요합니다.
proc hpsplit data=titan.new_train seed=123; class New_Sex New_Pclass New_Name New_Age_Group New_Fare_Group New_Embarked; model survived = New_Sex New_Pclass New_Name New_Age_Group New_Fare_Group New_Family New_Embarked; output out=test; code file = "C:/Users/help/Downloads/titanic/model_DT.sas"; run;
앞서 작성한 model_DT.sas를 사용하기 위해 다음과 같은 코드를 사용하여 Test 데이터를 만든 모델에 적합시킵니다.
data scored_DT; set titan.new_test; %include 'C:/Users/help/Downloads/titanic/model_DT.sas'; run;
여기서도 로지스틱 회귀분석 처럼 일정 확률값 이상을 생존 ('1') / 사망 ('0') 으로 지정합니다. 그리고 Kaggle에 제출하기 위해 Passenger와 Survived만 남겨둡니다.
data Titan.Test_Scored_DT; set scored_DT; if P_Survived > 0.5 then Survived = 1; else Survived = 0; keep PassengerId Survived; run;
마지막으로 Kaggle에 제출하기 위해 proc export를 사용하여 Result_DT.csv를 생성한 뒤 제출합니다.
proc export data=Titan.Test_Scored_DT file='C:/Users/help/Downloads/titanic/Result_DT.csv' replace; run;
제출 결과 0.76315로 기존 모델보다 약간 떨어지지만 베이스라인 모델과 비슷한 성능인 것을 볼 수 있습니다. 다른 모델로 더 분석해서 좋은 결과를 얻어봅시다.
notion imagenotion image

2) SVM

이번에는 SVM 모델을 이용하여 분석을 해봅시다. SVM 모델을 만드는 코드는 다음과 같습니다. Proc hpsvm을 이용합니다. Data에는 분석 데이터 이름을 넣고, method는 activeset으로 지정합니다. kernel,rbf,k_par옵션을 지정한 뒤 변수의 속성에 맞게 변수를 정의합니다. target에는 타겟변수인 survived를 입력하고 마지막으로 output을 지정합니다. output변수는 스코어링에 사용됩니다.
proc hpsvm data=TITAN.New_TRAIN method=activeset; kernel rbf / k_par = 3.0; input New_Family New_Pclass New_Age_Group New_Fare_Group/level=ORDINAL; input New_Name New_Sex New_Embarked / level = nominal; target survived; output outclass=outclass outfit=outfit outest=outest; run;
SAS에서 SVM은 svmscore를 사용하여 스코어링을 진행합니다. data에 테스트 데이터를 입력한 뒤 out을 지정하고, 아까 생성했던 outclass/outfit/outest를 다음과 같이 입력합니다.
proc svmscore data=TITAN.NEW_TEST out=score_svm inclass=outclass infit=outfit inest=outest; run;
Kaggle에 제출하기 위해 다음과 같이 데이터 셋을 정리합니다. 현재 PassengerId와 _I_가 변수 순서가 바뀌어 있는데 제출양식과 맞추려면 Retain문을 사용하면 변수 위치를 변경할 수 있습니다.
DATA RESULT_SVM; RETAIN PassengerId _I_; SET SCORE_SVM; RENAME _I_ = Survived; KEEP PassengerId _I_; RUN;
마지막으로 Kaggle에 제출하기 위해 proc export를 사용하여 Result_SVM.csv를 생성한 뒤 제출합니다.
PROC EXPORT DATA = Result_SVM Outfile = 'C:/Users/help/Downloads/titanic/Result_SVM.csv' DBMS=CSV REPLACE; RUN;
제출 결과 0.77751로 그전의 모델들보다 성능이 향상된 것을 볼 수 있습니다. 이제 마지막으로 RandomForest결과를 확인해봅시다.
 
notion imagenotion image

3) RandomForest

마지막으로 RandomForest 모델을 이용하여 분석을 해봅시다. RandomForest 모델을 만드는 코드는 다음과 같습니다. Proc hpforest를 이용합니다. 역시 Data에는 분석 데이터 이름을 넣고, RandomForest는 파라미터를 설정하기에 따라 결과값이 달라지지만 여기서는 다음과 같이 입력합니다. Target에는 Survived를 입력하고 Level에는 타겟변수의 속성을 입력합니다. 변수별 속성에 따라 input에 입력하고 마지막으로 스코어링을 위해 save file에 model_fit.bin을 생성합니다.
proc hpforest data=TITAN.New_TRAIN maxtrees= 100 vars_to_try=4 seed=2000 trainfraction=0.2 maxdepth=50 leafsize=3 alpha= 0.2; target Survived/ level=BINARY; input New_Sex New_Pclass New_Name New_Age_Group New_Fare_Group New_Family New_Embarked/ level=interval; ods output fitstatistics = fitstats; save file = "C:\Users\help\Downloads\titanic\model_fit.bin"; run;
Random Forest는 Proc hp4sore를 사용하여 스코어링을 진행합니다. data에 테스트 데이터를 입력한 뒤 ID를 PassengerId로 지정하고 아까 생성했던 model_fit.bin을 다음과 같이 입력합니다. 마지막으로 out에 Scored_RF로 입력하면 스코어링이 진행됩니다.
proc hp4score data=TITAN.NEW_TEST; ID PassengerId; score file= "C:\Users\help\Downloads\titanic\model_fit.bin" out=Scored_RF; run;
Kaggle에 제출하기 위해 다음과 같이 데이터 셋을 정리합니다.
DATA Result_RF; SET Scored_RF; RENAME I_Survived = Survived; KEEP PassengerId I_Survived; RUN;
마지막으로 Kaggle에 제출하기 위해 proc export를 사용하여 Result_SVM.csv를 생성한 뒤 제출합니다.
PROC EXPORT DATA = Result_RF Outfile = 'C:/Users/help/Downloads/titanic/Result_RF.csv' DBMS=CSV REPLACE; RUN;
제출 결과 0.78708로 모든 모델보다 가장 성능이 좋은 것을 볼 수 있습니다.
notion imagenotion image

3. 결론

SAS를 활용하여 로지스틱 회귀모델, 의사결정나무, SVM, RandomForest 4가지 모델을 활용해 보았습니다. 이제 조금은 데이터 분석과 가까워지고 Kaggle과 친근해 지셨나요? 모델을 전처리 하고 결과를 제출할때마다 결과가 좋아지는 것을 보면서 희열을 느끼시면서 조금 더 흥미가 생기시기를 바랍니다.
SAS를 활용하여 다양한 분석을 이용하는 방법을 아셨으니 이를 통해 많은 데이터 분석와 대회에 참여하실수 있으시면 좋겠습니다.