<jupyter_start><jupyter_text>"[SSUDA] 주택 가격 예측"- author: <NAME> - categories: [SSUDA, jupyter, kaggle, ridge, lasso, Regression] - image: images/210915.png https://www.kaggle.com/c/house-prices-advanced-regression-techniques캐글에 있는 주택 가격 예측 데이터 분석입니다.부스팅 모델들이 튜닝하는데 시간이 걸리기 때문에 좀 더 간단한 선형 회귀 모델을 사용하겠습니다.분류 관련 공부를 조금 해본 경험으로, 회귀에 기본인 선형 회귀모델을 이번 데이터를 이용해 공부해보겠습니다.이번 분석에 핵심 포인트는 숫자 변수 대부분이 치우쳐 있으므로 숫자 변수를 log_transform하는 것입니다.  데이터 불러오기 및 둘러보기<jupyter_code>import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib

import matplotlib.pyplot as plt
from scipy.stats import skew
from scipy.stats.stats import pearsonr


%config InlineBackend.figure_format = 'retina' #set 'png' here when working on notebook
%matplotlib inline
from google.colab import drive
drive.mount('/content/drive')
train = pd.read_csv("/content/drive/MyDrive/house/train.csv")
test = pd.read_csv("/content/drive/MyDrive/house/test.csv")
train.head()
train.info()
all_data = pd.concat((train.loc[:,'MSSubClass':'SaleCondition'],
                      test.loc[:,'MSSubClass':'SaleCondition']))<jupyter_output><empty_output><jupyter_text>id(고유번호)와 설명변수를 뺀 나머지 변수들을 전처리를 위해 all_data 변수로 합쳐주었습니다.  데이터 전처리 이 코드의 데이터 전처리는 화려하지 않습니다. 기본에 충실합니다.다음 3가지로 요약할 수 있습니다.1. 로그(기능 + 1)를 사용하여 오른쪽으로 꼬리가 긴 그래프를 변환합니다. 그러면 어느정도 정규화됩니다.2. 범주형 형상에 대한 더미 변수 생성3. 숫자 결측값(NaN)을 각 열의 평균으로 바꾸기 설명변수를 로그변환 해보기<jupyter_code>matplotlib.rcParams['figure.figsize'] = (12.0, 6.0)
prices = pd.DataFrame({"price":train["SalePrice"], "log(price + 1)":np.log1p(train["SalePrice"])})
prices.hist()<jupyter_output><empty_output><jupyter_text>로그변환 전 우측 꼬리가 두터운 느낌이였는데 잘 정규화 된 모습입니다.<jupyter_code>all_data.dtypes
# SalePrice변수 로그 변환
train["SalePrice"] = np.log1p(train["SalePrice"])

numeric_feats = all_data.dtypes[all_data.dtypes != "object"].index<jupyter_output><empty_output><jupyter_text>all_data.dtypes => 데이터 타입 나열. 여기서 인덱스는 변수이름이기 때문에 이런 방식으로 쉽게 추출.<jupyter_code>skewed_feats = train[numeric_feats].apply(lambda x: skew(x.dropna()))
skewed_feats = skewed_feats[skewed_feats > 0.75]
skewed_feats = skewed_feats.index

all_data[skewed_feats] = np.log1p(all_data[skewed_feats])<jupyter_output><empty_output><jupyter_text>shew = 왜도 값을 나타네는 함수. 왜도란 그래프가 비 대칭적인 모양인 것shew값이 큰 양수값이면 오른쪽으로 긴 꼬리를 가지는 분포를 가집니다.그러므로 shew값을 기준으로 로그변환을 할 변수를 찾을 수 있습니다.참고로 apply 함수는 파이썬 데이터 프레임에 적용하는 함수인데, 원하는 함수를 적용하고 싶을때 사용합니다.이때 apply 기본인자는 axis = 0이므로 열을 기준으로 함수를 적용합니다.<jupyter_code>all_data = pd.get_dummies(all_data)
all_data.head(5)<jupyter_output><empty_output><jupyter_text>get_dummies 함수로 모든 object형 값이 원핫인코딩 됐습니다.저번에 프로젝트 할 때 변수를 하나하나 입력했던 것이 생각나는데 더 편한 방식을 알게 되었습니다.<jupyter_code>all_data = all_data.fillna(all_data.mean())<jupyter_output><empty_output><jupyter_text>결측값이 있을때 각 열의 평균값으로 대체하는 일반적인 방식입니다.윗 코드와 마찬가지로 저번 프로젝트에서 열마다 함수를 돌려 사용했는데 더 편한 방식을 알게 됐습니다.<jupyter_code>X_train = all_data[:train.shape[0]]
X_test = all_data[train.shape[0]:]
y = train.SalePrice<jupyter_output><empty_output><jupyter_text>저번 프로젝트에서 트레인, 테스트 데이터에 각각 전처리를 적용했습니다.하지만 이 방법처럼 all_data로 묶고 한번에 전처리 하는 방식이 깔끔한 것 같습니다.  릿지 모델 선형 회귀 모델 적합을 하겠습니다.이때 라쏘, 릿지 방법을 모두 사용해서 최적의 rmse 값을 찾겠습니다.<jupyter_code>from sklearn.linear_model import Ridge, RidgeCV, ElasticNet, LassoCV, LassoLarsCV, Lasso
from sklearn.model_selection import cross_val_score

def rmse_cv(model):
    rmse= np.sqrt(-cross_val_score(model, X_train, y, scoring="neg_mean_squared_error", cv = 5))
    return(rmse)<jupyter_output><empty_output><jupyter_text>cross_val_score 함수는 교차 검증 후 정확도를 리스트로 보여줍니다.여기서 cv = 5 이기 때문에 5-fold로 교차검증 하게 됩니다.<jupyter_code>model_ridge = Ridge()<jupyter_output><empty_output><jupyter_text>릿지 모델의 주요 파라미터는 알파입니다.알파값이 높아지면 규제가 심해지고 과적합을 방지해줍니다.다만 너무 많이 높아지면 과소적합이 되기 때문에 적절한 값을 찾아야합니다.<jupyter_code>alphas = [0.05, 0.1, 0.3, 1, 3, 5, 10, 15, 30, 50, 75]
cv_ridge = [rmse_cv(Ridge(alpha = alpha)).mean() 
            for alpha in alphas]<jupyter_output><empty_output><jupyter_text>다양한 알파값을 릿지 함수에 적용시켰습니다.여기서 [값 for alpha in alphas] 는 for루프를 리스트 내에서 돌리는 것 입니다.<jupyter_code>cv_ridge = pd.Series(cv_ridge, index = alphas)
cv_ridge.plot(title = "Validation - Just Do It")
plt.xlabel("alpha")
plt.ylabel("rmse")<jupyter_output><empty_output><jupyter_text>시리즈에 plot를 하면 그래프가 생깁니다.이때 x축은 인덱스, y축은 본 값이 들어갑니다.알파값이 10일때 rmse값이 최소로, 알파는 10을 쓰는 것이 좋겠습니다.보통 규제하는 변수와 예측도를 측정하는 값간에 그래프는 U자형태가 잘 나옵니다.그 이유는 규제가 약할때와 쌜 때 각각 과소적합, 과적합이 일어나 예측도를 측정하는 값이 커지기 때문입니다.<jupyter_code>cv_ridge.min()<jupyter_output><empty_output><jupyter_text>최적의 rmse값은 0.1273입니다.  라쏘 모델 이번엔 라쏘 모델입니다.라쏘 모델은 릿지 모델과 다르게 영향력이 작은 변수의 계수를 0으로 만듭니다.변수 선택 과정까지 한번에 할 수 있다는 것이 장점입니다.<jupyter_code>model_lasso = LassoCV(alphas = [1, 0.1, 0.001, 0.0005]).fit(X_train, y)<jupyter_output><empty_output><jupyter_text>LassoCV 함수로 여러가지 알파값을 동시에 검정할 수 있습니다.<jupyter_code>model_lasso.alpha_
rmse_cv(model_lasso).mean()<jupyter_output><empty_output><jupyter_text>라쏘 모델이 rmse 값이 훨씬 낮아서 좋습니다.라쏘 모델을 사용하겠습니다.<jupyter_code>coef = pd.Series(model_lasso.coef_, index = X_train.columns)<jupyter_output><empty_output><jupyter_text>회귀 모델.coef_   => 계수를 컬럼순으로 보여줍니다.<jupyter_code>print("Lasso picked " + str(sum(coef != 0)) + " variables and eliminated the other " +  str(sum(coef == 0)) + " variables")<jupyter_output>Lasso picked 110 variables and eliminated the other 178 variables<jupyter_text>110개 변수는 선택되었고 178개 변수는 계수가 0, 즉 선택하지 않은 변수들입니다.<jupyter_code>coef
imp_coef = pd.concat([coef.sort_values().head(10),
                     coef.sort_values().tail(10)])
matplotlib.rcParams['figure.figsize'] = (8.0, 10.0)
imp_coef.plot(kind = "barh")
plt.title("Coefficients in the Lasso Model")<jupyter_output><empty_output><jupyter_text>sort_values() 함수는 범주형 변수의 히스토그램을 아는데 유용한 함수입니다.여기선 정렬기능으로 사용했는데, 정렬기능으로도 충분히 우수한 것을 보여줬습니다.정렬된 값 상위 10개, 하위 10개를 시각화했는데, 이 변수들이 핵심 변수입니다.왜냐하면 계수의 절대값이 큰 값이기 때문입니다.양의 값으로 가장 큰 GrLivArea변수는 면적으로 주택가격에 당연히 큰 영향을 끼칩니다.<jupyter_code>matplotlib.rcParams['figure.figsize'] = (6.0, 6.0)

preds = pd.DataFrame({"preds":model_lasso.predict(X_train), "true":y})
preds["residuals"] = preds["true"] - preds["preds"]
preds.plot(x = "preds", y = "residuals",kind = "scatter")<jupyter_output><empty_output><jupyter_text>잔차 그림도 큰 이상이 없습니다.<jupyter_code>model_lasso = Lasso(alpha = 0.0005).fit(X_train, y)
pred = model_lasso.predict(X_test)
pred2 = np.exp(pred) - 1
X_test['SalePrice'] = pred2
X_test['Id'] = test['Id']
final = X_test[['Id','SalePrice']]
final.to_csv('/content/drive/MyDrive/houselasso2.csv',encoding='UTF-8', index=False)<jupyter_output>/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:4: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  after removing the cwd from sys.path.
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:5: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  """<jupyter_text>알파값 0.0005인 라쏘 모델로 모델을 적합시키고 그 모델로 예측 파일을 만들었습니다.<jupyter_code><jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11723474436503574, 'fraction_numerical': 0.017179769103903245, 'mean_word_length': 5.520609318996415, 'pattern_counts': {'":': 4, '<': 80, '<?xml version=': 0, '>': 83, 'https://': 3, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '20', 'dir': 'jupyter-structured-clean-dedup', 'id': '663745', 'license': 'Apache-2.0', 'n_tokens_mistral': 4317, 'n_tokens_neox': 5018, 'n_words': 721, 'path': '_notebooks/2021-09-15-kagglessu1.ipynb', 'repo_name': 'KSY1526/myblog', 'size': '7284'}