본문 바로가기
IT - 코딩/AI, 예측모델

머신러닝 예측모델 선정하기 (인공지능 코테 예제)Adult Census Income Tutorial

by 조기정 2023. 10. 23.

Adult Census Income Tutorial

age: 나이 workclass: 고용 형태 fnlwgt: 사람의 대표성을 나타내는 가중치(final weight) education: 교육 수준 education.num: 교육 수준 수치 marital.status: 결혼 상태 occupation: 업종 relationship: 가족 관계 race: 인종 sex: 성별 capital.gain: 양도 소득 capital.loss: 양도 손실 hours.per.week: 주당 근무 시간 native.country: 국적 income: 수익 (예측해야 하는 값)

채점기준은 정밀도로 판단하며 답안 제출은 확률로 하시오.

path = r"C:\Users\Happy\Desktop\AI_project\자격증_빅분기 토스 _AICE\빅분기\input"
# .iloc로 하기 df[0] => 인덱스로 확인함..

#=======기본세팅 =======
# 시험환경 세팅 (코드 변경 X)
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

def exam_data_load(df, target, id_name="", null_name=""):
    if id_name == "":
        df = df.reset_index().rename(columns={"index": "id"})
        id_name = 'id'
    else:
        id_name = id_name
    
    if null_name != "":
        df[df == null_name] = np.nan
    
    X_train, X_test = train_test_split(df, test_size=0.2, random_state=2021)
    
    y_train = X_train[[id_name, target]]
    X_train = X_train.drop(columns=[target])

    
    y_test = X_test[[id_name, target]]
    X_test = X_test.drop(columns=[target])
    return X_train, X_test, y_train, y_test 
    
df = pd.read_csv(path+ "\\archive\\adult.csv")
X_train, X_test, y_train, y_test = exam_data_load(df, target='income', null_name='?')

X_train.shape, X_test.shape, y_train.shape, y_test.shape

여기까지기 기본적인 빅분기 실기 시험 과정 문제라고 생각하면 된다. 시험장에서는 y_test의 값이 존재하지 않는다는 점을 생각해두자.

import pandas as pd
import numpy as np

x_tr_len = len(X_train)
X_all = pd.concat([X_train,X_test],axis = 0)

나는 기본적으로 이런식의 코딩을 사용한다. 이렇게 둘다 묶어서 데이터를 본 다음 더미화 까지 해주면 한번에 처리 할 수 있다. 추후에 다시 학습데이터와 테스트 데이터 셋을 나누어야 하기 떄문에 concat전 len값이 얼만지 저장해둔다.

 

 

사진을 보니 데이터 값들의 na값이 존재하는 것들이 있다.

#명목형 변수의 경우에 있는 na값들은 의미가 있을 수 있다고 생각하여 False로 na값들을 바꾸어 더미화 전에 새로운 파생변수가 되게 하였다.
X_all.loc[X_all["workclass"].isna() == True,'workclass'] = "False"
X_all.loc[X_all["occupation"].isna() == True,'occupation'] = "False"
X_all.loc[X_all["native.country"].isna() == True,"native.country"] = "False"
X_all = X_all.drop(["id"],axis= 1)

해당 컬럼들은 na값에도 의미가 있을 수 있다고 생각하여 나는 더미화 전에 False라는 값을 새로 만들어 파생변수로 쓰이게끔 하였다.

 

데이터를 보아하니 이제 더미화 해도 괜찮을 것 같다.

X_all_1 = pd.get_dummies(X_all)
col = X_all_1.columns

from sklearn.preprocessing import StandardScaler,MinMaxScaler,LabelEncoder
Scaler = MinMaxScaler()

X_all_2 = Scaler.fit_transform(X_all_1)
X_all_2 = pd.DataFrame(X_all_2, columns = col)

더미화를 진행 한 후에 X_all_2라는 컬럼을 새로 만들어서 바로 스케일링 까지 해주었다.

랜덤 포레스트(트리기반)를 제외한 딥러닝, 머신러닝은 거의 대부분 스케일링을 해주어야 정확도가 상승한다.

 

# X_all_2 = X_all_1 # @ 의사결정 나무일 경우만 (의사결정 나무는 분리하기 때문에 범위가 넓으면 오히려 좋을수도 있다.)

x_train = X_all_2[:x_tr_len]
x_test = X_all_2[x_tr_len:]

LE = LabelEncoder()
y_train["income"] = LE.fit_transform(y_train["income"])

 

y_train의 값이 라벨링이 안되어 있는 것을 볼 수 있다. 

# X_all_2 = X_all_1 # @ 의사결정 나무일 경우만 (의사결정 나무는 분리하기 때문에 범위가 넓으면 오히려 좋을수도 있다.)

x_train = X_all_2[:x_tr_len]
x_test = X_all_2[x_tr_len:]

LE = LabelEncoder()
y_train["income"] = LE.fit_transform(y_train["income"])

때문에 라벨인코딩을 먼저 실행한다.

## 제출용 모델 
from sklearn.ensemble import GradientBoostingClassifier
from xgboost import XGBRFClassifier
model = XGBRFClassifier()
model.fit(x_train,y_train["income"])
pred = model.predict(x_test)
prob = model.predict_proba(x_test)
pred = LE.inverse_transform(pred) # 라벨인코더 역변환.

pd.DataFrame({"pred":pred,"prob":prob[:,1],"id":X_test.id}).to_csv("수험번호.csv",index = False)

이런식으로 prob[:,1]로 확율 값만 먼저 분류하고, pred(예측값)은 인버스 라벨인코딩으로 원래값을 뽑아낸다

 

y_test["income"] = LE.transform(y_test["income"])# 실제 정밀도 보려고
print("실제 정밀도(알수 x)",precision_score(y_test["income"],model.predict(x_test)))

실제 정밀도를 보기위해서 인코딩 된 값과 실제 값, 그리고 예측값을 비교해본 결과 이런 값이 나온다 하지만 시험장에서는 이렇게 확인이 불가하다. 따라서 다른 방법으로 내 모델이 적합한지를 확인을 할 수 있다.

 

일단 위 코드를 모두 셀로 정리하면 아래와 같다

import pandas as pd
import numpy as np

x_tr_len = len(X_train)
X_all = pd.concat([X_train,X_test],axis = 0)


# print(X_all.describe())

# print(X_all["workclass"].value_counts())
# print(X_all["occupation"].value_counts())
# print(X_all["native.country"].value_counts())

#명목형 변수의 경우에 있는 na값들은 의미가 있을 수 있다고 생각하여 False로 na값들을 바꾸어 더미화 전에 새로운 파생변수가 되게 하였다.
X_all.loc[X_all["workclass"].isna() == True,'workclass'] = "False"
X_all.loc[X_all["occupation"].isna() == True,'occupation'] = "False"
X_all.loc[X_all["native.country"].isna() == True,"native.country"] = "False"
X_all = X_all.drop(["id"],axis= 1)
# print(X_all.info())

X_all_1 = pd.get_dummies(X_all)
col = X_all_1.columns

from sklearn.preprocessing import StandardScaler,MinMaxScaler,LabelEncoder
Scaler = MinMaxScaler()

X_all_2 = Scaler.fit_transform(X_all_1)
X_all_2 = pd.DataFrame(X_all_2, columns = col)

# X_all_2 = X_all_1 # @ 의사결정 나무일 경우만 (의사결정 나무는 분리하기 때문에 범위가 넓으면 오히려 좋을수도 있다.)

x_train = X_all_2[:x_tr_len]
x_test = X_all_2[x_tr_len:]

LE = LabelEncoder()
y_train["income"] = LE.fit_transform(y_train["income"])

# ## 모델 선정 하기 
# a = int(np.floor(x_tr_len/10))
# a = x_tr_len - a
# x_train_1 = x_train[:a]
# x_val_1 = x_train[a:]
# # print(x_train_1.index)
# # print(x_val_1.index)
# y_train_1 = y_train[:a]
# y_val_1 = y_train[a:]

# from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier
# from xgboost import XGBRFClassifier,XGBClassifier
# model = XGBClassifier()
# model.fit(x_train_1,y_train_1["income"])
# pred = model.predict(x_val_1)
# # prob = model.predict_proba(x_val_1)

from sklearn.metrics import precision_score

# print("모델 설명력",model.score(x_train_1,y_train_1["income"]))
# print("정밀도",precision_score(y_val_1["income"],pred))

# y_test["income"] = LE.transform(y_test["income"])
# print("실제 정밀도(알수 x)",precision_score(y_test["income"],model.predict(x_test)))


## 제출용 모델 
from sklearn.ensemble import GradientBoostingClassifier
from xgboost import XGBRFClassifier
model = XGBRFClassifier()
model.fit(x_train,y_train["income"])
pred = model.predict(x_test)
prob = model.predict_proba(x_test)
pred = LE.inverse_transform(pred) # 라벨인코더 역변환.

pd.DataFrame({"pred":pred,"prob":prob[:,1],"id":X_test.id}).to_csv("수험번호.csv",index = False)

y_test["income"] = LE.transform(y_test["income"])# 실제 정밀도 보려고
print("실제 정밀도(알수 x)",precision_score(y_test["income"],model.predict(x_test)))

====================================모델 적합도 모의검정=======================================

위 코드를 보면 모델 선정하기로 놔둔 부분이 있다 이 부분으로 내 모델이 얼마나 적합한지를 먼저 판단하고 최적의 모델로 하여금 학습하고 뿌려주어야 할 것이라고 생각한다.

tip

1. 시험장 환경은 커다란 모델을 사용할 수가 없다. 자원이 부족하기 때문에 따라서 같은 모델에 데이터가 어느정도 늘어난다고 성능에 영향을 크게 미치지는 않을 것으로 보인다.

2. 사실은 하이퍼 파라미터를 조정하는 것보다 기본적인 모델을 사용하는 것이 좋다고 한다. 따라서 시험 전략 부분에 있어서는 다양한 모델을 비교해 보는 것이 좋을 것이라는 생각이 든다.

(필자는 해당 방법으로 빅분기 인공지능 시험 부분에서 만점을 받았다.)

 

import pandas as pd
import numpy as np

x_tr_len = len(X_train)
X_all = pd.concat([X_train,X_test],axis = 0)


# print(X_all.describe())

# print(X_all["workclass"].value_counts())
# print(X_all["occupation"].value_counts())
# print(X_all["native.country"].value_counts())

#명목형 변수의 경우에 있는 na값들은 의미가 있을 수 있다고 생각하여 False로 na값들을 바꾸어 더미화 전에 새로운 파생변수가 되게 하였다.
X_all.loc[X_all["workclass"].isna() == True,'workclass'] = "False"
X_all.loc[X_all["occupation"].isna() == True,'occupation'] = "False"
X_all.loc[X_all["native.country"].isna() == True,"native.country"] = "False"
X_all = X_all.drop(["id"],axis= 1)
# print(X_all.info())

X_all_1 = pd.get_dummies(X_all)
col = X_all_1.columns

from sklearn.preprocessing import StandardScaler,MinMaxScaler,LabelEncoder
Scaler = MinMaxScaler()

X_all_2 = Scaler.fit_transform(X_all_1)
X_all_2 = pd.DataFrame(X_all_2, columns = col)

# X_all_2 = X_all_1 # @ 의사결정 나무일 경우만 (의사결정 나무는 분리하기 때문에 범위가 넓으면 오히려 좋을수도 있다.)

x_train = X_all_2[:x_tr_len]
x_test = X_all_2[x_tr_len:]

LE = LabelEncoder()
y_train["income"] = LE.fit_transform(y_train["income"])

# ## 모델 선정 하기 
a = int(np.floor(x_tr_len/10))
a = x_tr_len - a
x_train_1 = x_train[:a]
x_val_1 = x_train[a:]
# print(x_train_1.index)
# print(x_val_1.index)
y_train_1 = y_train[:a]
y_val_1 = y_train[a:]

from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier
from xgboost import XGBRFClassifier,XGBClassifier
model = GradientBoostingClassifier()
model.fit(x_train_1,y_train_1["income"])
pred = model.predict(x_val_1)
# prob = model.predict_proba(x_val_1)

from sklearn.metrics import precision_score

print("모델 설명력",model.score(x_train_1,y_train_1["income"]))
print("정밀도",precision_score(y_val_1["income"],pred))

y_test["income"] = LE.transform(y_test["income"])
print("실제 정밀도(알수 x)",precision_score(y_test["income"],model.predict(x_test)))


# ## 제출용 모델 
# from sklearn.ensemble import GradientBoostingClassifier
# from xgboost import XGBRFClassifier
# model = XGBRFClassifier()
# model.fit(x_train,y_train["income"])
# pred = model.predict(x_test)
# prob = model.predict_proba(x_test)
# pred = LE.inverse_transform(pred) # 라벨인코더 역변환.

# pd.DataFrame({"pred":pred,"prob":prob[:,1],"id":X_test.id}).to_csv("수험번호.csv",index = False)

# y_test["income"] = LE.transform(y_test["income"])# 실제 정밀도 보려고
# print("실제 정밀도(알수 x)",precision_score(y_test["income"],model.predict(x_test)))

위 방법으로 테스트 후 모델 이름만 바꾸면서 설명력과 정확도를 비교하면 된다. 

 

처음 문제에서 정확도로 모델의 성능을 평가한다고 했으니 확인하는 것이고 설명력으로 어느정도 적합성을 판단하여 둘의 차이가 크지 않은 모델을 선택하는 것이 좋다고 생각된다.

 

아무것도 하지 않고 비교하는 방법은 아래와 같다.

tr_len = len(X_train)
X_all = pd.concat([X_train,X_test],axis = 0)

X_all = X_all.drop(["id"],axis = 1)
# na값이 있는 행들 넣고 했는데 오히려 좋았다..
# X_all = X_all.drop(["id","workclass","occupation","native.country"],axis = 1) 
X_all_1 = pd.get_dummies(X_all)
col = X_all_1.columns

from sklearn.preprocessing import MinMaxScaler
Sclaer =  MinMaxScaler()
X_all_2 = Sclaer.fit_transform(X_all_1)
X_all_2 = pd.DataFrame(X_all_2,columns = col)

x_train = X_all_2[:tr_len]
x_test = X_all_2[tr_len:]

x_train_1 = x_train[:-2604]
x_val = x_train[-2604:]

Y_all = pd.concat([y_train,y_test],axis = 0)

# Y_all.reset_index(drop = True)

# Y_all.loc[Y_all["income"]== "<=50K","income"] = 1.0
# Y_all.loc[Y_all["income"]== ">50K","income"] = 0.0


import sklearn.preprocessing
LE = sklearn.preprocessing.LabelEncoder()
Y_all['income'] = LE.fit_transform(Y_all['income'])

y_train = Y_all[:tr_len]
y_test = Y_all[tr_len:]

y_train_1 = y_train[:-2604]
y_val = y_train[-2604:]

from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier()# 이진 분류 모델
# model = XGBClassifier(eval_metric = "logloss" )
model.fit(x_train_1 ,y_train_1["income"])
pred = model.predict(x_val)

print(model.score(x_train ,y_train["income"]))
print(model.score(x_val ,y_val["income"]))

print(
sklearn.metrics.accuracy_score(y_val["income"],model.predict(x_val)) ,
sklearn.metrics.f1_score(y_val["income"],model.predict(x_val))
)

print(
sklearn.metrics.accuracy_score(y_test["income"],model.predict(x_test)) ,
sklearn.metrics.f1_score(y_test["income"],model.predict(x_test))
)

https://github.com/GiJungCho/AI_project_/blob/main_/%EC%9E%90%EA%B2%A9%EC%A6%9D_%EB%B9%85%EB%B6%84%EA%B8%B0%20%ED%86%A0%EC%8A%A4%20_AICE/%EB%B9%85%EB%B6%84%EA%B8%B0/T1%EB%B9%85%EB%B6%84%EA%B8%B0%EB%B3%B5%EC%8A%B5-Copy1.ipynb