데이터분석/학습기록지

빅데이터분석기사 제2작업형 팁 복기

Null to One 2025. 6. 6. 14:50

1. train test 범주형 데이터 범주 비교

unique한 값의 개수가 같다고 하더라도 종류가 다르다면 인코딩 과정에서 이를 고려해주어야 하므로 중요합니다.

 

범주형 데이터 수가 적으면 일일이 비교해도 상관은 없는데 5개 6개... 점점 더 늘어날수록 여기에 시간이 불필요하게 많이 소모됩니다.

 

따라서 다음과 같은 방법을 사용합니다.

 

cols = train.select_dtypes(include="object").columns

 

for col in cols:

     set_train = set(train[col])

     set_test = set(test[col])

     

     same = set_train == set_test

     if same:

           print(col, "카테고리 동일함")

     else:

           print(col, "카테고리 다름")

 

카테고리 다른 경우가 많지 않으면 삭제하고 학습 시도해보기. 성능 낮으면 추후에 카테고리 다시 포함해서 작성하기(카테고리 종류 달라도 train하고 test 함께 합쳐서 인코딩하는 방법 쓰면 되므로)


 

2. 베이스라인 이후 개선

(1) 인코딩 방식 바꾸기

(2) 스케일링하기

* 주의할 점은, 만약 ID가 수치형으로 저장되어 있다면 ID는 제외하고 스케일링하는게 낫습니다. ID의 경우, 트리 계열 모델 사용시 모델에서 알아서 중요도를 낮게 책정하므로 삭제 안해도 상관 없긴 합니다. 일부 도메인의 경우 오히려 ID가 중요한 경우도 있으므로, 무작정 삭제하는 것은 지양합니다.

(3) 모델 파라미터 바꾸어보기 - n_estimators, max_depth 등등...

(4) 만약 문자열 컬럼에서 숫자랑 문자가 섞여 문자열로 지정되어 있는 경우라면, 정보량을 함유하고 있는 숫자 부분을 떼어내어 수치형 데이터로 바꾸는 편이 도움이 될 수 있습니다. 또한, 일부 레코드가 특정 정보를 함유하는 경우, 이를 이진 데이터로 바꾸어 컬럼을 새로 생성해주면 좋습니다.

ex)

1. train['weight'] = train['weight'].str.replace('kg', '').astype(float) -> kg을 제거하고 몸무게를 수치형 데이터로. (test에 대해서도 동일하게 진행)

2. train['supplements'] = train['trainer']str.contains('supplements').astype(int)

    train['trainer'] = train['trainer'].str.replace('supplements', '')

    -> 보충제를 섭취하는 trainer 들의 경우 supplements 컬럼이 1로 표시되도록. 그리고 기존의 trainer 컬럼에서           supplements라는 문자열을 제거해주기. (test에 대해서도 동일하게 진행)

 

*그 외: 혹시 말도 안되게 점수가 시작부터 1 나와 버렸다 -> 운 좋게 validation 데이터가 예쁘게 나누어진 경우일 수 있으므로 cross validation 시도해보기

cross_val_score의 경우, train_test_split과 같은 sklearn.model_selection에서 import하면 됩니다. cross_val_score를 사용할 시 train_test_split을 할 필요 없습니다.

용례:

from sklearn.ensemble import RandomForestClassifier

from sklearn.model_selection import cross_val_score

rf = RandomForestClassifier(random_state=0)

score = cross_val_score(rf, train, target, cv=5, scoring='f1_macro')

print(score.mean()) # score의 경우, cross validation을 5번 진행한( train과 validation 조합을 5번 바꾸어 수행한 결과 5번) 점수들이 리스트 형태로 반환됩니다. 따라서, mean()을 사용하여 평균 점수를 내주어야 합니다.

 

#점수를 내고 난 후에 모델 학습 및 test 데이터 예측을 통해 나온 답안을 제출합니다.

rf.fit(train, target)

pred = rf.predict(test)

result = pd.DataFrame({'pred': pred})

result.to_csv('result.csv', index=False)

 

(5) target data가 심각한 불균형인 경우

class_weight = 'balanced'로 설정하여 부족한 데이터에 가중치 부여해주기

 

(6) 활용해보기 좋은 단서

-> train.head()와 train.info()로 데이터를 확인해봤는데, 그냥 수치형으로 저장해도 될 것 같은데 object타입인 경우들. 이런 경우 데이터 전처리에 활용할 법한 좋은 단서가 있을 수 있습니다.

예를 들어, engine volume(엔진 용량)의 경우, train.head()로 확인해보니 3.5, 5.9, 6.7 ... 이런 식의 값들이라 float타입이어도 될 것 같은데 info를 확인해보니 object타입으로 지정된 경우. 왜 그런지 value_counts를 확인해 보았을 때, 활용할 법한 단서가 존재할 수도 있습니다. 일부 데이터에는 특정한 문자열이 들어가 있다거나 하는 식으로 말이죠.

그런 경우 컬럼을 파생해서 학습에 활용하면 성능이 개선될 수 있습니다.

 


 

3. 베이스라인 작성 전 웬만하면 거치는 EDA

(1) shape 살펴보기

(2) info 살펴보기

(3) target 기술통계 확인하기

(4) train과 test 범주 데이터 카테고리 비교하기

(5) 결측치 유무 확인

 


4. 평가지표 관련

precision, recall, f1_score의 경우, positive label이 무엇인지 명시해주기.

단, target이 0과 1로 변환되어 있는 상황이라면 굳이 명시해줄 필요는 없음. target이 '>100', '<=100'과 같은 형태일 경우, pos_label = '>100'으로 명시적으로 지정해주어야 함.

Macro, Micro 등등 문제 조건 잘 보고 모델 점수 매겨보기. train_test_split을 쓸 경우 metrics에서 average를 'macro'나 'micro' 등으로 지정해야 합니다. cross_val_score를 쓸 경우 scoring을 지정합니다.

 

어떤 클래스가 양성 클래스에 해당하는지 잘 모르겠는 경우 -> model.classes_ 활용하기

 

다중 평가지표의 경우, precision, recall, f1_score의 평가지표는 macro, micro, weighted 중 선택해서 계산합니다.

macro: 각 클래스에 대한 점수의 평균

micro: 모든 클래스에 대한 점수의 평균

weighted: 각 클래스에 대한 점수의 가중 평균

 

MAPE -> 직접 계산하는 방식을 추천.

mean_absolute_percentage error 공식:     (abs((y_true - y_pred)/y_true)).mean() * 100

 

MAPE 문제점: true값에 만약 0이 존재한다면, 분모가 0이기 때문에 계산하는 것이 불가능. 따라서, 결과값에 크게 영향을 주지 않되 분모가 0이 되는 것을 방지하는 아주 작은 값을 더하는 방식을 사용할 수 있습니다.

ex) small_value = 1e-100 (abs((y_true-y_pred)/y_true)).mean()*100