본문 바로가기
Hobby/Hobby_4 - Coding

[자격증] 빅분기 실기 - 1. 유형 파악 및 풀이 시도

by 와우멍 2021. 6. 13.

안녕하세요 와우멍입니다.

오늘부터는 빅데이터 분석기사 실기 벼락치기 과정을 포스팅하겠습니다.

빅데이터분석기사 필기는 일단 벼락치기를 마무리 한 후 다시 정리해서 후기 올리겠습니다.


 

빅데이터 분석기사 실기 개요

 빅분기 실기 과정의 개요는 아래와 같습니다.

 

 실기에서의 주요 항목을 보면 기본적으로 수집 - 전처리 - 모형구축 - 평가로 필기보다는 더 합리적인 과정이라고 생각합니다. (필기 범위에서는 종류 외우는 것 때문에 너무 힘들었었습니다 ㅠㅠ)

 Kdata 홈페이지에 맛보기 예제가 업로드되었는데, https://dataq.goorm.io/exam/116674/%EC%B2%B4%ED%97%98%ED%95%98%EA%B8%B0/quiz/1에서 수행해볼 수 있습니다. 

  100점 만점에서 60점 이상을 취득하면 합격이 되는데, 문항별 배점을 보면 작업형 2문제를 풀기만이라도 하고 단답형에서 몇개만 건지면 합격할 수 있을 것 같습니다.

 그럼 거두절미하고 주어진 예제를 풀어보겠습니다.


빅데이터 분석기사 실기 예제 풀이

 

작업형 1. mtcars 데이터셋(mtcars.csv) qsec 컬럼을 최소최대 척도(Min-Max Scale)로 변환한 후 0.5보다 큰 값을 가지는 레코드 수를 구하시오.

답변 1) 일단 Pandas를 사용하지 않고 numpy만 이용해서 먼저 풀어봤습니다.

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd
import numpy as np
 
test = pd.read_csv("data/mtcars.csv")
qsec = test['qsec']
 
qsec_min_scale = qsec - np.min(qsec)
qsec_scale = qsec_min_scale/np.max(qsec_min_scale)
 
output = np.where(qsec_scale>0.5)[0]
 
print(len(output))
cs

코드 해설

 Min값과 Max값을 각각 0과 1로 만들어야 하니,

 7 Line에서 Min값이 0이 되도록 np.min(array)을 array의 모든 값에서 빼준 다음

 8 Line에서 Max값이 1이 되도록 np.max(array)를 모든 값에 나눠주면 일단 Min-Max scale이 완료됩니다.

 10 Line에서 마지막으로 0.5보다 큰 값들을 찾아야 하니, 간단하게 np.where(array 조건)로 0.5보다 큰 성분들이 몇개 있는지 찾아서 출력해줍니다. 다만, 여기서 주의할 사항은 np.where( )의 출력값은 [ ]로 한번 쌓여있기 때문에 뒤에 [0]을 해주지 않으면 1차원 list 형태를 갖는 것으로 나타납니다.

추가

 근데 np.where( )함수를 사용하지 않더라도 단순히 

1
print(qsec_scale[qsec_scale>0.5])
cs

 로 하더라도 qsec_scale 배열의 내용물 중 0.5보다 큰 값만 출력이 되니 더 간단히 답을 얻을 수 있겠네요.

 어쨋든 답은 9가 되겠습니다!


작업형 2. 아래는 백화점 고객의 1년 간 구매 데이터이다. 고객 3500명에 대한 학습용 데이터(y_train.csv, X_train.csv)를 이용하여 성별예측 모형을 마든 후, 이를 평가용 데이터(X_test.csv)에 적용하여 얻은 2482명 고객의 성별 예측값(남자일 확률)을 다음과 같은 형식(custid, gender)의 CSV 파일로 생성하시오. (제출한 모델의 성능은 ROC-AUC 평가지표에 따라 채점)

답변 1) 일단 이것 저것 스텝바이스텝으로 혼자 해본 답입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import pandas as pd
from sklearn.linear_model import LogisticRegression
 
x_test = pd.read_csv("data/X_test.csv")
x_train = pd.read_csv("data/X_train.csv")
y_train = pd.read_csv("data/y_train.csv")
 
cust_id = x_test.loc[:,'cust_id']
 
index_ch = ['주구매지점''주구매상품''cust_id']
x_train.drop(index_ch, axis=1, inplace=True)
y_train.drop('cust_id', axis=1, inplace=True)
x_test.drop(index_ch, axis=1, inplace=True)
 
x_train.loc[:, '환불금액'= x_train.loc[:,'환불금액'].fillna(0)
x_test.loc[:, '환불금액'= x_test.loc[:,'환불금액'].fillna(0)
 
model = LogisticRegression()
model.fit(x_train,y_train)
 
predict = model.predict_proba(x_test)
predict_man = predict[:,1]
 
output = pd.DataFrame({'cust_id':cust_id, 'gender':predict_man})
output.set_index('cust_id', inplace=True)
output.to_csv('수험번호.csv',sep='\t')
 
 

코드 해설

이번 풀이과정에서는 pandas와 LogisticRegression만 사용했습니다.

 4~6 line에서는 각 파일들을 불러왔습니다. 다만, 윈도우에서 한국어가 들어간 파일을 불러올 경우에는 encoding 옵션을 걸어줘야 오류없이 로딩이 됩니다.

 (x_test = pd.read_csv("data/X_test.csv", encoding='cp949')) 이런식으로요!

 8 line은 답변제출시 'cust_id'를 붙여야 하기 때문에 미리 백업합니다.

 10~13 line은 성별을 예측하는 모델을 만드는 과정에서 사용하지 않을 column을 제거하는 과정입니다. '주구매지점'과 '주구매상품'은 문자값이 들어있어서 one-hot-encoding을 통해 사용할 수도 있지만, 각 column이 수십개의 값을 갖기 때문에 비효율적일 것 같아 주관적으로 제거했습니다. 그리고 'cust_id'는 그냥 순서대로 번호를 붙인 것이기 때문에 모델학습과정에서 오히려 악영향을 미칠 것 같아 제거했습니다. 제거하는 과정에서 inplace=True는 기존 dataframe 자체를 바꿔버리겠다는 옵션입니다.

 15~16 line은 데이터 내에 NaN값이 들어있는 행들이 있었는데 다행히도 '환불금액' column에만 NaN이 있었습니다. 그런데 환불금액이 없다는 것은 환불하지 않았다는 것이라 볼 수 있으니, NaN 부분을 0으로 채워넣었습니다.

 18~19 line은 결과를 남1/여0 두개의 값으로 분류를 하는 것이니 Logistic Regression를 선택하고 모델을 만들었습니다.

 21 line에서 위에서 만든 모델을 테스트셋(x_test)에 적용하여 고객별 성별 예측 확률을 산출하고

 22 line에서 문제에서 요구한 남자일 확률을 slicing 했습니다.

 24~25 line에서 답안의 형식에 맞게 cust_id와 남자일 확률을 하나의 Data frame으로 정리하고, 자동으로 부여되는 index를 없애기 위해 'cust_id'를 index로 설정하고

 26 line에서 저장을 하며 마무리했습니다.

결과는 다음과 같습니다.

>> '수험번호.csv'


 다시 공부한 내용: Dataframe 다루기! 

  - df.iloc[행, 열 숫자] 는 pandas dataframe을 slicing하는 도구

  - df.loc[행, 열 문자]dictionary 기능 + 조건표현을 이용하는 느낌 

 *그런데 x_train.loc['cust_id']를 하면 에러가 나고, x_train.loc[:, 'cust_id']를 해야 출력이 됨. 즉, cust_id는 column index니 두번째 성분으로 입력해줘야지.

 *Dataframe 다루는 것이 numpy의 slicing보다 표현이 더 자유롭고 직관적이네요!!

 

  - df.drop(인덱스, axis= , inplace= ) 를 통해 필요없는 열을 날려버릴 수 있다.

  인덱스는 list 형태로 지울 index를 입력해주고, axis는 column을 날릴 것인지 row를 날릴 것인지에 따라 정해주면 됩니다. 그리고 drop한 Dataframe을 새로 선언해줄 수도 있지만, 그냥 기존의 df에서 날린 후 그대로 저장하는 옵션이 바로 inplace=True 이다. 

  - x_train.loc[x_train['환불금액'].isnull()].fillna(0)

이렇게 처리하면 x_train의 환불금액 column에서 null인 부분을 찾아 0으로 채운다는 의미가 된다. df.isnull()을 하면 null인 부분은 True를 반환하게 되니 x_train.loc[조건]에서 True인 부분만 반환이 되어 nan값을 갖는 성분만 반환이 되고 그 부분들을 fillna( )를 통해 값을 채우는 것!

근데 이렇게 하면 바꿔치기 할 때 과정이 조금 복잡해진다. 그러니 간단하게

x_train['환불금액'][x_train['환불금액'].insull()] = 0 으로 NaN 값을 갖는 애들을 다 찾아서 0으로 바꿔주는 방법이 있고

x_train.loc[:, '환불금액'] = x_train.loc[:,'환불금액'].fillna(0) 으로 직접 nan 찾아 0으로 입력해주는 함수를 쓸 수도 있다.


일단 제가 처음 도전한 답변은 이 정도로 정리하겠습니다.

 

해보면서 느낀 점은 다음과 같습니다.

 1. 데이터 전처리를 위해, Dataframe을 불러오고 잘라내고 수정하는 등의 핸들링이 자유자재로 이루어져야 할 것 같다.

 2. sklearn에서 모델 세우고, 값을 예측하는 과정은 정형화되어 있으니 사용할만한 라이브러리를 잘 외우자..

 3. numpy보다는 pandas를 사용하는 과정에 익숙해지자.

 

 그럼 다음 포스팅에서 또 봽겠습니다!

댓글