빅데이터분석기사/작업형2

[작업형2] 고객의 성별이 남자일 확률 구하기(분류)

seo0seok 2023. 6. 15. 10:37

// 퇴근후딴짓 님의 강의를 참고하였습니다. //

 

Dataset :

X_test.csv
0.17MB
X_train.csv
0.23MB
y_train.csv
0.02MB

문제) 백화점 고객의 1년간 구매 데이터에서 고객의 성별 예측값(남자일 확률)을 다음과 같은 형식의 CSV 파일로 생성하시오.

- cust_id : 고객 ID 

- gender : 성별 (0: 여자, 1: 남자)

 

1. 데이터 불러오기

import pandas as pd

X_train = pd.read_csv("X_train.csv", encoding="euc-kr")
y_train = pd.read_csv("y_train.csv")
X_test = pd.read_csv("X_test.csv", encoding="euc-kr")

→ 시험환경에서는 encoding="euc-kr"가 없어도 된다.

 

2. EDA

# 데이터 크기
X_train.shape, y_train.shape, X_test.shape

실행 결과 : 
((3500, 10), (3500, 2), (2482, 10))

 

# 데이터 샘플 X_train
X_train.head(3)

→ X_train은 cust_id, 총구매액, 최대구매액, 환불금액 등 10개의 열로 이루어져있다.

 

# 데이터 샘플 y_train
y_train.head(3)

→ y_train은 cust_id와 gender 2개의 열로 이루어져있다.

 

# 데이터 샘플 X_test
X_test.head(3)

→ X_test는 X_train과 동일하게 10개의 열로 이루어져있다.

 

# [Tip] 컬럼이 다보이지 않을 때
pd.set_option('display.max_columns', None)

→ 시험환경에서 컬럼이 전부 보이지 않을때 사용

 

# 결측치 확인 train
X_train.isnull().sum()

실행 결과 : 
cust_id       0
총구매액          0
최대구매액         0
환불금액       2295
주구매상품         0
주구매지점         0
내점일수          0
내점당구매건수       0
주말방문비율        0
구매주기          0
dtype: int64
# 결측치 확인 test
X_test.isnull().sum()

실행 결과 : 
cust_id       0
총구매액          0
최대구매액         0
환불금액       1611
주구매상품         0
주구매지점         0
내점일수          0
내점당구매건수       0
주말방문비율        0
구매주기          0
dtype: int64

→ X_train과 X_test에서 환불금액에 결측치가 있는 것을 확인

 

# 기초 통계
X_train.describe()

 

# [Tip] 지수표현식(과학적표기법) 사용 X
pd.options.display.float_format = '{:.2f}'.format
X_train.describe()

→ e+03과 같은 지수표현식을 사용하고 싶지 않을때 사용한다.

→ '{: .2f}'에서 숫자를 변경하여 소수점 자리 설정이 가능하다.

 

# 기초 통계 object
X_train.describe(include='object')

→ X_train의 명목형 변수는 주구매상품, 주구매지점 2가지 이다.

→ 주구매상품이 42개의 고유값으로 이루어져있다.

# 기초 통계 object (x_test)
X_test.describe(include='object')

→ X_test의 명목형 변수 역시 주구매상품, 주구매지점 2가지 이다.

→ 주구매상품이 41개의 고유값으로 이루어져있다.

 

→ count : 행의 개수

→ unique : 상품 종류의 수 (고유값)

→ top : 제일 많은 상품 종류

→ freq : 제일 많은 상품 빈도수

 

# 고유값 (train)
X_train['주구매상품'].unique()

실행 결과 : 
array(['기타', '스포츠', '남성 캐주얼', '보석', '디자이너', '시티웨어', '명품', '농산물', '화장품',
       '골프', '구두', '가공식품', '수산품', '아동', '차/커피', '캐주얼', '섬유잡화', '육류',
       '축산가공', '젓갈/반찬', '액세서리', '피혁잡화', '일용잡화', '주방가전', '주방용품', '건강식품',
       '가구', '주류', '모피/피혁', '남성 트랜디', '셔츠', '남성정장', '생활잡화', '트래디셔널',
       '란제리/내의', '커리어', '침구/수예', '대형가전', '통신/컴퓨터', '식기', '소형가전', '악기'],
      dtype=object)
# 고유값 (test)
X_test['주구매상품'].unique()

실행 결과 : 
array(['골프', '농산물', '가공식품', '주방용품', '수산품', '화장품', '기타', '스포츠', '디자이너',
       '시티웨어', '구두', '캐주얼', '명품', '건강식품', '남성정장', '커리어', '남성 캐주얼', '축산가공',
       '식기', '피혁잡화', '모피/피혁', '섬유잡화', '트래디셔널', '차/커피', '육류', '가구', '아동',
       '셔츠', '액세서리', '젓갈/반찬', '대형가전', '일용잡화', '통신/컴퓨터', '생활잡화', '주방가전',
       '란제리/내의', '남성 트랜디', '보석', '주류', '침구/수예', '악기'], dtype=object)

→ .unique() 함수로 해당 열의 고유값을 얻을 수 있다.

 

# [Tip] set 타입으로 변경하면 비교 가능함
a = set(X_train['주구매상품'].unique())
b = set(X_test['주구매상품'].unique())
print(a - b)
print(a.difference(b))

실행 결과 : 
{'소형가전'}
{'소형가전'}

→ 위에서 보았듯 X_train의 주구매상품은 42개, X_test의 주구매상품은 41개로 이루어져있다.

→ set 타입으로 변경 후 두 변수를 빼거나, differnce() 함수를 사용하면 1개의 주구매상품이 무엇인지 쉽게 알 수 있다.

 

# target(label) 값 확인
y_train['gender'].value_counts()

실행 결과 : 
0    2184
1    1316
Name: gender, dtype: int64

→ y_train 성별 컬럼은 0(여자) 2184개, 1(남자) 1316개의 행으로 이루어져있다.

 

3. 데이터 전처리

# 결측치처리
X_train = X_train.fillna(0) # 환불금액 0값으로 채움
X_test = X_test.fillna(0)

→ X_train과 X_test의 결측치(환불금액)을 0으로 채운다.

 

# id 삭제함 (단 test의 id값은 csv파일을 생성할 때 필요함으로 옮겨 놓음)
X_train = X_train.drop(['cust_id'], axis=1)
cust_id = X_test.pop('cust_id')

→ X_train에서 필요없는 cust_id 열을 삭제한다.

→ cust_id 열은 csv파일 제출시 필요하기 때문에 cust_id 변수에 따로 저장해 둔다.

→ pop()은 해당 컬럼을 꺼내 변수에 값을 넘겨준 다음 X_test에서 cust_id 열을 삭제해준다.

 

4. 피처엔지니어링

# 라벨 인코더
from sklearn.preprocessing import LabelEncoder

cols = ['주구매상품', '주구매지점']
for col in cols:
  le = LabelEncoder()
  X_train[col] = le.fit_transform(X_train[col])
  X_test[col] = le.transform(X_test[col])

X_train.head()

→ 주구매상품과 주구매지점 같은 [명목형 변수]를 LabelEncoder 작업을 한다.

 

# MinMaxScaler 수치형
from sklearn.preprocessing import MinMaxScaler
cols = ['총구매액', '최대구매액', '환불금액', '내점일수', '내점당구매건수', '주말방문비율', '구매주기']
scaler = MinMaxScaler()
X_train[cols] = scaler.fit_transform(X_train[cols])
X_test[cols] = scaler.fit_transform(X_test[cols])
X_train.head()

→  총구매액, 최대구매액 등의 [수치형 변수]를 MinMaxScaler 작업을 한다.

 

5. 데이터 분리

# 검증 데이터 분리
from sklearn.model_selection import train_test_split
X_tr, X_val, y_tr, y_val = train_test_split(X_train,
                                            y_train['gender'],
                                            test_size = 0.2,
                                            random_state = 2022
)
X_tr.shape, X_val.shape, y_tr.shape, y_val.shape

실행 결과 : 
((2800, 9), (700, 9), (2800,), (700,))

→ X_train, y_train 데이터를 훈련용과 검증용 데이터로 분리한다.

→ test_size : val(검증용 데이터)의 비율 설정

→ random_state : 분리 시 마다 일정하게 하기 위한 설정

 

6. 모델링

# 모델링 & 하이퍼파라미터 튜닝 & 앙상블
from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier(random_state=2022)
model.fit(X_tr, y_tr)
pred = model.predict_proba(X_val)

→ 랜덤포레스트 모델을 사용해 훈련용 데이터를 학습시키고 검증용 데이터로 예측을 실시한다.

→ random_state를 설정하지 않으면 훈련할때마다 예측 결과가 다르게 나온다.

→ predict_proba 함수는 예측 확률을 나타낸다.

 

# 예측 결과 확인
pred

실행 결과 : 
array([[0.66, 0.34],
       [0.37, 0.63],
       [0.89, 0.11],
       ...,
       [0.61, 0.39],
       [0.55, 0.45],
       [0.45, 0.55]])

→ 예측 결과에서 왼쪽값이 0(여자)일 확률, 오른쪽값이 1(남자)일 확률을 나타낸다.

 

7. 평가(self)

# 검증 데이터 셋으로 평가
from sklearn.metrics import roc_auc_score
roc_auc_score(y_val, pred[:,1])

실행 결과 :
0.6098414179104478

→ roc_auc_score를 통해 검증 데이터(y_val)로 평가시 60.98%의 예측률을 나타낸다.

→ pred[:, 0] : 여자일 확률 / pred[:, 1] : 남자일 확률

 

8. 예측 및 제출

# test 데이터 예측
pred = model.predict_proba(X_test)
pred

실행 결과 :
array([[0.47, 0.53],
       [0.75, 0.25],
       [0.77, 0.23],
       ...,
       [0.57, 0.43],
       [0.5 , 0.5 ],
       [0.54, 0.46]])

→ 테스트 데이터(X_test)로 예측을 실시한다.

 

# 데이터 프레임 만들기
submit = pd.DataFrame(
    {
        'cust_id' : cust_id,
        'gender' : pred[:,1]
    }
)

→ 데이터프레임을 만들어 pop()을 통해 빼두었던 cuit_id와 남자일 확률을 예측한 pred[:,1] 값을 담는다.

 

# 샘플 데이터 확인
submit.head()

 

# csv 생성
submit.to_csv("수험번호.csv", index=False)

→ .to_csv() 함수를 사용해 제출용 csv 파일을 생성한다.

→ index = False를 하지 않을시 인덱스 열이 자동으로 생성되어 문제에서 제시한 cust_id, gender 2개의 열로 되지 않는다.

 

9. 제대로 제출 되었는지 확인

pd.read_csv("수험번호.csv")

→ 생성한 csv 파일을 불러와 제대로 제출 되었는지 확인한다.