6/28 Today I Learned -1

boks·2024년 6월 28일
post-thumbnail

📖 학습한 내용

  • 보스턴 집값 예측 모델 생성

📖 핵심내용

📌 보스턴 집값 예측 모델 생성

  • object형 확인. 첫행확인하여서 확실하게 하기
object_col = train.select_dtypes(include='object').columns.tolist()

# 혹시 1,000 이런 문자형인 숫자가 있을 수 있으니깐 첫행만 확인
for col in object_col:
  print(train[col].values[0])
  • corr() 은 범주형에 할 수 없다. 제거 후 코릴레이션
numeric_train  = train.select_dtypes(include=['number']).columns.tolist().copy()
  • 결측치가 모두 범주형데이터인 것을 확인
# 결측치 모두 범주형데이터인 것을 확인
for col in null_col:
  print(train[col].value_counts().index.tolist())
  • 결측치를 채우기 위해서 디시전 트리를 사용
# 결측치를 모두 디시전 트리로 채우는 함수

def fill_null_tree(data, null_col):
  number_column = data.select_dtypes(include='number').columns.tolist() # 숫자형 컬럼 리스트로 만들기
  df = data[number_column].copy() # 숫자형 컬럼만 뽑아서 df 생성

  non_missing_df = df[~data[null_col].isnull()] # df에서 결측이 아닌 행으로 구성
  missing_df = df[data[null_col].isnull()] # df에서 결측인 행으로 구성

  y_non_missing_df = data[null_col][~data[null_col].isnull()] # 결측이있는 컬럼의, 결측이 아닌 행으로 구성

  dt = DecisionTreeClassifier()
  dt.fit(non_missing_df, y_non_missing_df) # 결측 아닌 행들로 훈련
  pred_dt = dt.predict(missing_df) # 결측있는 행으로 구성된 데이터 넣으면, 결측치를 채울 예측값이 나온다.

  id = data[null_col][data[null_col].isnull()].index # 결측 있는 컬럼으로 인덱스 뽑기
  data.loc[id, null_col] = pred_dt # 결측치 채우기

-> 이번 과제에서는 이렇게 진행하였지만, 사실 틀린방법이다.
시계열데이터가 아닌 다른 독립변수들은 결측치를 채울때 다른 독립변수들에게 의존한다면, 다중공선성의 문제가 생긴다.
독립변수끼리 서로 영향을 많이 끼친다면, 그것은 하나의 특성에 가중치가 많이 붙게되는 효과가 있는 것이다. 이는 올바른 학습을 방해하는 요인 중 하나이다.

  • 범주형 데이터 나누기 : value_counts로 컬럼 하나하나 들여다보면서, 특징을 파악하여 분류하기

  • 순서형 데이터 채우기 : 인코딩을 위해서 낯은순서에서 높은 순서로 변경

def create_ordinal_mapping(ordinal_features, ordinal_values):
    ordinal_mapping = {}
    for var, values in zip(ordinal_features, ordinal_values):
        ordinal_mapping[var] = {value: idx for idx, value in enumerate(values)}
    return ordinal_mapping


ordinal_mapping = create_ordinal_mapping(ordinal_features, ordinal_values)

for col, mapping in ordinal_mapping.items():
    train_onehoted[col] = train_onehoted[col].map(mapping)
  • 테스트 데이터 결측치 채우기
    -> 반드시 트레인 데이터 기준으로 해야한다.
# 트레인 데이터의 평균으로 채우기

for col in null_col_test_num:
  test[col].fillna(train[col].mean(), inplace=True)

-> 트레인 데이터의 평균으로 테스트 데이터 결측치 채우기

-> 트레인 데이터 훈련한 디시전트리로 결측치 채우기

# 트레인데이터 기준으로 훈련시켜서 테스트 데이터 결측치 채워넣기

def fill_null_test(train, test, null_col):
  a = train.drop(columns=null_col, axis=1)
  number_columns = a.select_dtypes(include='number').columns.tolist()

  missing_df = test[test[null_col].isnull()][number_columns]

  dt = DecisionTreeClassifier()
  number_columns = a.select_dtypes(include='number').columns.tolist()

  dt.fit(a[number_columns], train[null_col])

  pred_dt = dt.predict(missing_df)

  id = test[null_col][test[null_col].isnull()].index # 결측 있는 컬럼으로 인덱스 뽑기
  test.loc[id, null_col] = pred_dt # 결측치 채우기
  test[null_col].isnull().sum()
  
# 각 결측치 있는 컬럼에 대해 반복 수행
for col in null_col_test:
  fill_null_test(train, test, col)
  • 모델만들어 성능테스트
# 모델 파라미터 -> 성능평가 ->베스트 모델

def grid_cv(x_train, y_train, x_test, model, param):
    grid_model = GridSearchCV(model, param,
                              cv=5, n_jobs=-1, verbose=2,
                              scoring='neg_mean_squared_error',
                              return_train_score=True,
                             )
    grid_model.fit(x_train, y_train)
    best_grid_model = grid_model.best_estimator_
    print(f'Used column list: {len(x_train.columns)}개  {x_train.columns.tolist()}')
    print('최상의 매개변수: ', grid_model.best_params_)

    # 최적 모델에 대해 다시 교차 검증 수행 (MAE 사용)
    cv_scores = cross_val_score(best_grid_model, x_train, y_train, cv=5, scoring='neg_mean_absolute_error')
    cv_mae = -cv_scores.mean()
    pred = best_grid_model.predict(x_test)

    print(f"Cross-Validated Mean Absolute Error (CV MAE): {cv_mae:.5f}")

    return pred
xgb_params_1 = {
    "max_depth": [None, 2,],
    "learning_rate" : [0.01, 0.05],
    "n_estimators": [100, 150],
    'alpha': [0, 0.1],
    'lambda': [1, 2],
}
xgb_1 = XGBRegressor(objective='reg:squarederror',booster = "gbtree", random_state=42)
grid_xgb_1 = grid_cv(train_onehoted, y_train, test_onehoted, xgb_1, xgb_params_1)
  • 결과 데이터프레임으로 만들기
test_onehoted['y_pred'] = grid_xgb_1
test_onehoted.head()

📖 흥미로운 점 / 새로 알게된 점

  • 시계열 데이터가 아닌 경우 절대 다른 독립변수들을 학습시켜서 결측치를 채우면 안된다. 사실 서로 상관관계나 회귀계수가 없는 컬럼인데, 그런 관계가 생길 수 있기때문이다. 또한 피처간에 다중공선성이 커지고 분석에 문제가 생기므로 하면 안된다.

📖 어려운 부분

  • 테스트데이터의 결측치를 트레인 데이터의 결측치로 채워 넣는 것이 어려웠다.

📖 기타

  • 미니 프로젝트였다. 혼자서 처음부터 끝까지 쭉 해봤다. 매우 매우 오래걸렸지만, 많이 성장했다고 느낄 수 있었다.
profile
설계엔지니어의 변신

0개의 댓글