728x90

선형 회귀 모델은 기본적으로 오차항은 정규 분포를 따르고 있어

 

데이터의 분포가 정규분포를 따르는 것이 좋다.

 

 

하지만 분포가 한 방향으로 치우쳐진(왜도 != 0) 경우 예측 성능이 저하 될 수 있다.

 

-> 정규화 수행

 

1. 표준 정규 분포를 따르도록 정규화

- StandardScaler 사용

 

2. 최소 0, 최대 1이 되도록 정규화

- MinMaxScaler 사용

 

3. 로그 변환을 이용한 정규화

- 입력 데이터에 로그 변환 적용 -> 출력 값은 정규 분포를 따르게 됨.

 

 

 

 

 

데이터 변환 방법에 따른 성능을 비교하기 위해

 

 

이전의 선형 회귀 평가 함수에서 알파 값별 rmse를 반환하도록 약간 수정

 

def get_linear_reg_eval(model_name, params=None, X_data = None, y_target=None, visualize=False, columns=None):
    fig, axs = plt.subplots(figsize=(18, 6), nrows=1, ncols=5)
    coeff_df = pd.DataFrame()
    print("#### {} ####".format(model_name))
    params = params.copy()
    rmses = []
    for pos, param in enumerate(params):
        if model_name == "Ridge": model = Ridge(alpha=param)
        elif model_name == "Lasso": model= Lasso(alpha=param)
        elif model_name == "ElasticNet": model = ElasticNet(alpha=param, l1_ratio=0.7)
        
        neg_mse_scores = cross_val_score(model, X_data, y, scoring="neg_mean_squared_error",cv = 5)
        rmse_scores = np.sqrt(-1 * neg_mse_scores)
        avg_rmse = np.mean(rmse_scores)
        rmses.append(avg_rmse)
        print("# alpha = {} #".format(param))
        print("neg_mse_socres : {}".format(neg_mse_scores))
        print("rmse_scores : {}".format(rmse_scores))
        print("avg_rmse : {}\n".format(avg_rmse))
        
        model.fit(X_data, y_target)
        coeff = pd.Series(model.coef_, index=columns)
        colname="alpha="+str(param)
        coeff_df[colname] = coeff

        coeff = coeff.sort_values(ascending=False)
        axs[pos].set_title(colname)
        axs[pos].set_xlim(-3, 6)
        sns.barplot(x=coeff.values, y=coeff.index, ax=axs[pos])
    
    if visualize == False:
        plt.close()
    return rmses

 

 

보스턴 집값 데이터를 사용하기 위해

 

보스턴 데이터 함수 정의

def get_boston_Xy():
    boston = load_boston()
    df = pd.DataFrame(data=boston.data, columns=boston.feature_names)
    df["PRICE"] = boston.target
    df.head()
    X = df.iloc[:,:-1]
    y = df.iloc[:, -1]
    return X, y

 

 

입력한 method에 따라 변환 하는 데이터 변환 함수 정의

 

def get_scaled_data(method=None, input_data=None):
    if method == "Standard":
        scaled_data = StandardScaler().fit_transform(input_data)
    elif method == "MinMax":
        scaled_data = MinMaxScaler().fit_transform(input_data)
    elif method == "Log":
        scaled_data = np.log1p(input_data)
    else:
        scaled_data = input_data
    return scaled_data

 

 

데이터 변환 방법과 alpha 값에 따른 rmse 비교 데이터 프레임 반환 함수 정의

 

def comparision_data_transform(model_name=None, X_data=None, y_target=None, alphas=None):
    scale_methods = ["Standard", "MinMax", "Log", None]
    df_columns = alphas.copy()
    df_columns.insert(0, "scaled_method")
    print("df_columns ", df_columns)
    df = pd.DataFrame(columns=df_columns)
    for scale_method in scale_methods:
        scaled_data = get_scaled_data(method=scale_method, input_data=X)
        print("# scale method = {}#".format(scale_method))
        print("----------------------")
        #print(scaled_data)
        rmses = get_linear_reg_eval(model_name, params=alphas, X_data=scaled_data, y_target=y, columns=X.columns)
        rmses.insert(0, scale_method)
        rmse_series = pd.Series(rmses, index=df_columns)
        df = df.append(rmse_series.to_frame().T)
    
    return df

 

 

 

 

실행 코드

X, y = get_boston_Xy()
alphas = [0.1, 1, 10, 100]
model_name = "Ridge"
df = comparision_data_transform(model_name=model_name, X_data=X, y_target=y, alphas=alphas)

 

 

결과

- 대부분 Log 변환을 하였을때 좋은 성능을 보였음.

- Log 변환을 수행하고, 알파 값이 1일때 rmse가 4.67623으로 최적의 결과를 얻음

 

 

 

300x250

+ Recent posts