('데이터 전처리' 카테고리에서 '데이터 전처리 정리 및 실습'  파트에서 발생한 오류)

# 특징 선택과 모델 하이퍼 파라미터 튜닝
from sklearn.ensemble import RandomForestClassifier as RFC
from xgboost import XGBClassifier as XGB
from lightgbm import LGBMClassifier as LGBM
from sklearn.feature_selection import *
from sklearn.model_selection import ParameterGrid
from sklearn.metrics import f1_score

# 모델 파라미터 그리드 설계
model_parameter_grid = dict()
model_parameter_grid[RFC] = ParameterGrid({'max_depth':[2, 3, 4],
                                          'n_estimators':[50, 100]})
model_parameter_grid[XGB] = ParameterGrid({'max_depth':[2, 3, 4],
                                          'n_estimators':[50, 100],
                                          'learning_rate':[0.05, 0.1, 0.15, 0.2]})
model_parameter_grid[LGBM] = ParameterGrid({'max_depth':[2, 3, 4],
                                           'n_estimators':[50, 100],
                                           'learning_rate':[0.05, 0.1, 0.15, 0.2]})
# 튜닝 시작
best_score = 0
for k in range(30, 5, -1):
    s_x_train = x_train[pvals.iloc[:k].index]
    s_x_test = x_test[pvals.iloc[:k].index]
    for M in model_parameter_grid.keys():
        for P in model_parameter_grid[M]:
            model = M(**P).fit(s_x_train, y_train)
            pred = model.predict(s_x_test)
            score = f1_score(y_test, pred)
            if score > best_score:
                best_score = score
                best_feature = s_x_train.columns
                best_model = M
                best_parameter = P

print(best_score)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [78], in <cell line: 3>()
      6 for M in model_parameter_grid.keys():
      7     for P in model_parameter_grid[M]:
----> 8         model = M(**P).fit(s_x_train, y_train)
      9         pred = model.predict(s_x_test)
     10         score = f1_score(y_test, pred)

File ~\AppData\Roaming\Python\Python39\site-packages\xgboost\core.py:575, in _deprecate_positional_args.<locals>.inner_f(*args, **kwargs)
    573 for k, arg in zip(sig.parameters, args):
    574     kwargs[k] = arg
--> 575 return f(**kwargs)

File ~\AppData\Roaming\Python\Python39\site-packages\xgboost\sklearn.py:1357, in XGBClassifier.fit(self, X, y, sample_weight, base_margin, eval_set, eval_metric, early_stopping_rounds, verbose, xgb_model, sample_weight_eval_set, base_margin_eval_set, feature_weights, callbacks)
   1352     expected_classes = np.arange(self.n_classes_)
   1353 if (
   1354     self.classes_.shape != expected_classes.shape
   1355     or not (self.classes_ == expected_classes).all()
   1356 ):
-> 1357     raise ValueError(
   1358         f"Invalid classes inferred from unique values of `y`.  "
   1359         f"Expected: {expected_classes}, got {self.classes_}"
   1360     )
   1362 params = self.get_xgb_params()
   1364 if callable(self.objective):

ValueError: Invalid classes inferred from unique values of `y`.  Expected: [0 1], got [-1  1]

 

클래스가 0부터 시작해야 하기 때문에 발생합니다(버전 1.3.2부터 필요함)

이를 해결하는 쉬운 방법은 sklearn.preprocessing 라이브러리의 LabelEncoder를 사용하는 것입니다.

 

솔루션

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y_train = le.fit_transform(y_train)

y_train의 레이블을 새로 인코딩 한 뒤 학습을 하니 해결이 가능했다.

 

이후 모델 평가 시 주의사항

le.inverse_transform으로 인코딩된 값을 다시 디코딩해서 새로 들어오는 데이터 즉, 테스트 데이터의 레이블 값(y_test)의 원본 형태인 -1과 1로 맞추어야 score를 구할 수 있음

# 튜닝 시작
best_score = 0
for k in range(30, 5, -1):
    s_x_train = x_train[pvals.iloc[:k].index]
    s_x_test = x_test[pvals.iloc[:k].index]
    for M in model_parameter_grid.keys():
        for P in model_parameter_grid[M]:
            model = M(**P).fit(s_x_train, y_train)
            pred = model.predict(s_x_test)
            pred = le.inverse_transform(pred)
            score = f1_score(y_test, pred)
            if score > best_score:
                best_score = score
                best_feature = s_x_train.columns
                best_model = M
                best_parameter = P

print(best_score)
print('\n')
print(best_feature)
print('\n')
print(best_model)
print('\n')
print(best_parameter)

 

출처:https://stackoverflow.com/questions/71996617/invalid-classes-inferred-from-unique-values-of-y-expected-0-1-2-3-4-5-got

[학습자료]

패스트캠퍼스 “파이썬을 활용한 데이터 전처리 Level UP 올인원 패키지 Online.”

 

확률 모델 비용 민감 모델 구축하는 과정에서 cut off value 값에 따른 재현율과 정밀도 변화를 확인하는 과정에서의 오류

 

일단, 로지스틱 회귀모델을 만들고 cut off value를 조정하는 함수를 작성했다.

# cut off value를 조정하는 함수 작성
def cost_sensitive_model(model, cut_off_value, x_test, y_test):
    probs = model.predict(x_test)
    probs = pd.DataFrame(probs, columns = model.classes_)
    pred_y = 2 * (probs.iloc[:, -1] > cut_off_value) -1
    recall = recall_score(y_test, pred_y)
    accuracy = accuracy_score(y_test, pred_y)
    return recall, accuracy

그 후, cut off value에 따른 재현율과 정확도의 변화를 확인하기 위해 plot을 찍는 과정에서 오류가 발생했다.

# cut off value에 따른 recall과 accuracy 변화 확인
from matplotlib import pyplot as plt
import numpy as np

cut_off_value_list = np.linspace(0, 1, 101)
recall_list = []
accuracy_list = []

for c in cut_off_value_list:
    recall, accuracy = cost_sensitive_model(model, c, x_test, y_test)
    recall_list.append(recall)
    accuracy_list.append(accuracy)

%matplotlib inline
plt.plot(cut_off_value_list, recall_list, label = 'recall')
plt.plot(cut_off_value_list, accuray_list, label = 'accuracy')
plt.legend()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [38], in <cell line: 9>()
      7 accuracy_list = []
      9 for c in cut_off_value_list:
---> 10     recall, accuracy = cost_sensitive_model(model, c, x_test, y_test)
     11     recall_list.append(recall)
     12     accuracy_list.append(accuracy)

Input In [37], in cost_sensitive_model(model, cut_off_value, x_test, y_test)
      2 def cost_sensitive_model(model, cut_off_value, x_test, y_test):
      3     probs = model.predict(x_test)
----> 4     probs = pd.DataFrame(probs, columns = model.classes_)
      5     pred_y = 2 * (probs.iloc[:, -1] > cut_off_value) -1
      6     recall = recall_score(y_test, pred_y)

File ~\anaconda3\lib\site-packages\pandas\core\frame.py:694, in DataFrame.__init__(self, data, index, columns, dtype, copy)
    684         mgr = dict_to_mgr(
    685             # error: Item "ndarray" of "Union[ndarray, Series, Index]" has no
    686             # attribute "name"
   (...)
    691             typ=manager,
    692         )
    693     else:
--> 694         mgr = ndarray_to_mgr(
    695             data,
    696             index,
    697             columns,
    698             dtype=dtype,
    699             copy=copy,
    700             typ=manager,
    701         )
    703 # For data is list-like, or Iterable (will consume into list)
    704 elif is_list_like(data):

File ~\anaconda3\lib\site-packages\pandas\core\internals\construction.py:351, in ndarray_to_mgr(values, index, columns, dtype, copy, typ)
    346 # _prep_ndarray ensures that values.ndim == 2 at this point
    347 index, columns = _get_axes(
    348     values.shape[0], values.shape[1], index=index, columns=columns
    349 )
--> 351 _check_values_indices_shape_match(values, index, columns)
    353 if typ == "array":
    355     if issubclass(values.dtype.type, str):

File ~\anaconda3\lib\site-packages\pandas\core\internals\construction.py:422, in _check_values_indices_shape_match(values, index, columns)
    420 passed = values.shape
    421 implied = (len(index), len(columns))
--> 422 raise ValueError(f"Shape of passed values is {passed}, indices imply {implied}")

ValueError: Shape of passed values is (392, 1), indices imply (392, 2)

​

함수를 정의한 코드를 자세히 보니 실수를 했었다...

cut off value를 활용하기 위해서는 predict 예측값이 아닌 predict_proba로 예측확률을 봤어야 했는데 predict로 코드를 짜서 shape가 맞질 않았던 것이다.

predict_proba를 쓰면 2차원 배열에 각 클래스를 예측한 확률로 나와서 shape가 (392, 2)로 나오는데  predict를 쓰면 1차원 배열에 클래스를 예측한 값 즉, -1과 1이 나오기 때문에 shape가 (392, 1)로 나와서 작성했던 함수에 'cut off value에 따른 recall과 accuracy 변화 확인' 코드가 먹히지 않았던 것이다. 

다시말해, 만든 함수는 predict를 사용해서 1차원 배열이지만, 함수 작성 후 내가 쓴 코드는 2차원 배열꼴을 넣어서 shape가 맞지 않아 오류가 발생했던 것이었다.

 

코드를 쓸 때 나타나는 사소한 실수지만 뭐가 잘못된지 모르고 10분 이상을 코드를 재확인했다... 발견해서 다행 :)

 

 

cut off value를 조정하는 함수 작성 수정 코드

# cut off value를 조정하는 함수 작성
def cost_sensitive_model(model, cut_off_value, x_test, y_test):
    probs = model.predict_proba(x_test)
    probs = pd.DataFrame(probs, columns = model.classes_)
    pred_y = 2 * (probs.iloc[:, -1] >= cut_off_value) -1
    recall = recall_score(y_test, pred_y)
    accuracy = accuracy_score(y_test, pred_y)
    return recall, accuracy

2번째 줄에 predict를 predict_proba로 수정해서 문제 해결 완료~

'Errors' 카테고리의 다른 글

xgboost 지도학습 중 발생한 error  (0) 2023.01.21

+ Recent posts