ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ML] [Kaggle] House Prices - Advanced Regression Techniques
    __Data Analysis/__Kaggle 2021. 4. 21. 00:40

     

    수업 중 개별 프로젝트(과제)

     

    - data_description.txt

    sample_submission.csv

    test.csv

    - train.csv

     

    • 요약 :

    - 데이터 : 1460 row X 81 columns

    - Goal : predict the sales price for each house.(the value of the SalePrice variable.)

    - Metric : Submissions are evaluated on Root-Mean-Squared-Error (RMSE) between the logarithm of the predicted value and the logarithm of the observed sales price.

     

     

     

     


    라이브러리 불러오기

    import numpy as np
    import pandas as pd
    import seaborn as sns
    import matplotlib.pyplot as plt
    import warnings
    warnings.filterwarnings(action='ignore')
    
    from sklearn.model_selection import train_test_split, GridSearchCV, KFold, StratifiedKFold
    from sklearn.model_selection import cross_val_score, cross_validate     
    from sklearn.svm import SVC
    from xgboost import XGBClassifier
    from lightgbm import LGBMClassifier
    from sklearn.linear_model import Ridge, Lasso, ElasticNet, LinearRegression, LogisticRegression
    from sklearn.metrics import mean_squared_error
    
    pd.set_option('display.max_columns',None)
    pd.set_option('display.max_row',None)

    1. DATA LOAD

    dataset = pd.read_csv('train.csv')

     

     

    2. EDA

    print(dataset.head())
    print(dataset.describe())

     

     

    - Alley 결측치 보임. 전체 데이터 결측치 확인 필요

    - MSSubClass, OverallQual 등 카테고리성 피쳐 확인 필요 

    - LotArea, BsmtFinSF1 등 스케일링 필요한 피쳐 확인 필요

    - 불필요한 피쳐 삭제 & 데이터 변환 필요

     

     

    상관분석 - 무슨 피쳐가 중요할까

    df.corrwith(df["SalePrice"]).sort_values(ascending=False)
    SalePrice       1.000000 집 가격
    OverallQual     0.790982 집 재료 및 마감 평가
    GrLivArea       0.708624 지상 거실 면적(평방 피트)
    GarageArea      0.623431 차고 크기(평방 피트)
    TotalBsmtSF     0.613581 지하 총 면적(평방 피트)
    1stFlrSF        0.605852 1층 면적(평방 피트)
    FullBath        0.560664 등급? 이상의 전체 욕실
    TotRmsAbvGrd    0.533723 등급 이상의 총 방 (욕실 미포함)
    YearBuilt       0.522897 연식
    YearRemodAdd    0.507101 리모델링 날짜 (개조 또는 추가가없는 경우 시공 날짜와 동일)
    Fireplaces      0.466929 벽난로 수
    BsmtFinSF1      0.386420 완성 된 평방 피트
    LotFrontage     0.351799 부동산에 연결된 거리의 선형 피트
    2ndFlrSF        0.319334 2 층 평방 피트
    HalfBath        0.284108 등급? 이상의 절반 욕실
    LotArea         0.263843 로트 크기 (평방 피트)
    BsmtFullBath    0.227122 지하 전체 욕실
    BedroomAbvGr    0.168213
    BsmtFinSF2     -0.011378 유형 2 완성 된 면적 (평방 피트)
    BsmtHalfBath   -0.016844 지하 절반 욕실
    Id             -0.021917 -------------------------------------------------id가 왜 높지? 
    LowQualFinSF   -0.025606 저품질 마감 (모든 층) (평방 피트)
    OverallCond    -0.077856 집의 전반적인 상태를 평가
    MSSubClass     -0.084284 판매와 관련된 주거 유형
    KitchenAbvGr   -0.135907

     

     

    - 모든 피쳐가 필요해보이진 않으며, 우선 SalesPrice와 상관관계가 큰 피쳐가 중요도 높은 것으로 생각됨.

    - 따라서 우선 상관계수 높은 것만 데이터프레임 생성하고 점수가 안 좋으면 추가해가기

     

    high_corr = ['SalePrice', 'OverallQual', 'GrLivArea', 'GarageArea', 'TotalBsmtSF', 
    		'1stFlrSF', 'FullBath', 'TotRmsAbvGrd', 'YearBuilt', 'YearRemodAdd', 
            'Fireplaces', 'BsmtFinSF1', 'LotFrontage', '2ndFlrSF', 'HalfBath', 
            'LotArea', 'BsmtFullBath', 'BedroomAbvGr', 'BsmtFinSF2', 'BsmtHalfBath', 
            'Id', 'LowQualFinSF', 'OverallCond', 'MSSubClass', 'KitchenAbvGr'
    		]
    df = dataset.copy()[high_corr]

     

    피쳐 축소( -> 25개)

     

    print(df.head())
    print(df.describe())

     

    상관도 확인

    plt.figure(figsize=(15,12))
    sns.heatmap(df.corr(),annot=True, fmt='.2g') 

     

    결측치 확인

    df.isnull().sum()

    - 새로 생성한 데이터는 결측치 가진 피쳐가 1개. LotFrontage

    - LotFrontage :부동산에 연결된 거리의 선형 피트 -> 우선 중요하지 않아 보여 drop

    df = df.drop(['LotFrontage'],axis=1)
    # print(df.isnull().sum())  # 결측 피처 없음

     

    0 데이터 확인

    nan_dict = {"CNT":df.isin([0]).sum(),
                "RATE": df.isin([0]).sum()/df.shape[0] *100
    			}
    nan_df = pd.DataFrame(nan_dict)
    print(nan_df[nan_df["RATE"]>0].sort_values("CNT", ascending=False))

     

    카테고리성 피쳐 확인

    cate_feature = []
    no_cate = []
    for col in df.columns:
        if df[col].nunique() <= 40:
            print(col, df[col].unique())
            cate_feature.append(col)
        else:
            no_cate.append(col)
    print()
    print('개수: ',len(cate_feature))
    print('- 카테고리 피쳐 -', cate_feature, sep='\n')
    print('- 수치 피쳐 -',no_cate,sep='\n')

    분포도 확인 - histogram

    df.hist(figsize=(12,12))
    plt.show()

     

    결측치 없으니 일단 점수 내보기

    X_df = df.iloc[:,:-1]
    y_df = df.iloc[:,-1]
    X_train, X_val, y_train,y_val = train_test_split(X_df,y_df,test_size=0.3,shuffle=True, random_state=121)
    print(X_train.shape,X_val.shape,y_train.shape,y_val.shape)

    model1 = LinearRegression()
    model1.fit(X_train,y_train)
    pred = model1.predict(X_val)
    
    mse = mean_squared_error(y_val, pred, squared=True)
    rmse = mean_squared_error(y_val, pred, squared=False)
    print(f'MSE:{mse:.5f} , RMSE:{rmse:.5f}')
    # MSE:0.03584 , RMSE:0.18932

    아무런 전처리도 하지 않았고, 스케일링도 되지 않은 상태로 낸 점수

    - RMSE 점수가 0.189로 좋게 나왔다. Overfitting이 의심된다.

    - 스케일링 후 다시 점수 내보자.

                                 

     

     

     - - - - - - 21.04.20 - - - - - - 

     

     

     

    위 코드에선 아주 큰 실수가 있었다! 습관의 무서움

    이후 전처리와 가공을 더 하고 모델도 추가해 0.8이라는 점수를 봐서 캐글에 제출했다.

    - - 결과는 처참한 등수. 쓰기도 싫은 결과물

    왜 그럴까 싶어 주피터에서 pred 출력해보니, log 스케일 한것을 원래 스케일로 돌려놨음에도 1.0이라는 값들로 채워져있었다.

     

    구글에도 그런 질문글이 보이지 않아서 강사님께 도움을 청했다. 내 노트북을 보시더니 target이 X_val에 포함 되어있다는걸 발견해주셨다! ㅠㅠ 임의로 컬럼을 선택해 데이터프레임 생성할 때 target을 맨 앞에 뒀다는 걸 잊고 습관처럼 마지막 피쳐를 target으로 분리한 것이었다.

     

    다행히, 그걸 고쳤더니 캐글에서 정상 점수 획득. 

    새로운 공모전 시작하지만, 시간날 때 틈틈이 피쳐 추가하고 가공 다시해서 30% 까지 올려봅시다

     

     

     

    house_price_0421
    house_price_0421

     - - - - - - 21.04.21 - - - - - - 

    728x90

    댓글

Designed by Tistory.