EDA with Housing Price Prediction - Handling Continuous Variables

Page content

강의 홍보

I. 개요

  • 이제 본격적으로 Kaggle 데이터를 활용하여 분석을 진행한다.
  • 데이터는 이미 다운 받은 상태를 전제로 하며, 만약에 데이터가 없다면 이전 포스팅에서 절차를 확인하기 바란다. (미리보기 가능)

II. 구글 드라이브 연동

  • 구글 코랩을 시작하면 언제든지 가장 먼저 해야 하는 것은 드라이브 연동이다.
from google.colab import drive # 패키지 불러오기 
from os.path import join  

ROOT = "/content/drive"     # 드라이브 기본 경로
print(ROOT)                 # print content of ROOT (Optional)
drive.mount(ROOT)           # 드라이브 기본 경로 Mount

MY_GOOGLE_DRIVE_PATH = 'My Drive/Colab Notebooks/inflearn_kaggle/' # 프로젝트 경로
PROJECT_PATH = join(ROOT, MY_GOOGLE_DRIVE_PATH) # 프로젝트 경로
print(PROJECT_PATH)
/content/drive
Go to this URL in a browser: https://accounts.google.com/o/oauth2/auth?client_id=947318989803-6bn6qk8qdgf4n4g3pfee6491hc0brc4i.apps.googleusercontent.com&redirect_uri=urn%3aietf%3awg%3aoauth%3a2.0%3aoob&response_type=code&scope=email%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdocs.test%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive.photos.readonly%20https%3a%2f%2fwww.googleapis.com%2fauth%2fpeopleapi.readonly

Enter your authorization code:
··········
Mounted at /content/drive
/content/drive/My Drive/Colab Notebooks/inflearn_kaggle/
%cd "{PROJECT_PATH}"
/content/drive/My Drive/Colab Notebooks/inflearn_kaggle
  • 위 코드가 에러 없이 돌아간다면 이제 데이터를 불러올 차례다.
!ls
data  docs  source
  • 필자는 inflearn_kaggle 폴더안에 data, docs, source 등의 하위 폴더를 추가로 만들었다.
  • 즉, data 안에 다운로드 받은 파일이 있을 것이다.

III. 캐글 데이터 수집 및 EDA

  • 우선 데이터를 수집하기에 앞서서 EDA에 관한 필수 패키지를 설치하자.
import pandas as pd
import pandas_profiling
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.pyplot import figure
import seaborn as sns

from IPython.core.display import display, HTML
from pandas_profiling import ProfileReport
/usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
  import pandas.util.testing as tm
%matplotlib inline
import matplotlib.pylab as plt

plt.rcParams["figure.figsize"] = (14,4)
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['lines.color'] = 'r'
plt.rcParams['axes.grid'] = True 

(1) 데이터 수집

  • 지난 시간에 받은 데이터가 총 4개임을 확인했다.
    • data_description.txt
    • sample_submission.csv
    • test.csv
    • train.csv
  • 여기에서는 우선 test.csv & train.csv 파일을 받도록 한다.
train = pd.read_csv('data/train.csv')
test = pd.read_csv('data/test.csv')
print("data import is done")
data import is done

(2) 데이터 확인

  • Kaggle 데이터를 불러오면 우선 확인해야 하는 것은 데이터셋의 크기다.
    • 변수의 갯수
    • Numeric 변수 & Categorical 변수의 개수 등을 파악해야 한다.
  • Point 1 - train데이터에서 굳이 훈련데이터와 테스트 데이터를 구분할 필요는 없다.
    • 보통 Kaggle에서는 테스트 데이터를 주기적으로 업데이트 해준다.
  • Point 2 - 보통 test 데이터의 변수의 개수가 하나 더 작다.
train.shape, test.shape
((1460, 81), (1459, 80))
  • 그 후 train데이터의 상위 5개의 데이터만 확인한다.
display(train.head())
IdMSSubClassMSZoningLotFrontageLotAreaStreetAlleyLotShapeLandContourUtilitiesLotConfigLandSlopeNeighborhoodCondition1Condition2BldgTypeHouseStyleOverallQualOverallCondYearBuiltYearRemodAddRoofStyleRoofMatlExterior1stExterior2ndMasVnrTypeMasVnrAreaExterQualExterCondFoundationBsmtQualBsmtCondBsmtExposureBsmtFinType1BsmtFinSF1BsmtFinType2BsmtFinSF2BsmtUnfSFTotalBsmtSFHeating...CentralAirElectrical1stFlrSF2ndFlrSFLowQualFinSFGrLivAreaBsmtFullBathBsmtHalfBathFullBathHalfBathBedroomAbvGrKitchenAbvGrKitchenQualTotRmsAbvGrdFunctionalFireplacesFireplaceQuGarageTypeGarageYrBltGarageFinishGarageCarsGarageAreaGarageQualGarageCondPavedDriveWoodDeckSFOpenPorchSFEnclosedPorch3SsnPorchScreenPorchPoolAreaPoolQCFenceMiscFeatureMiscValMoSoldYrSoldSaleTypeSaleConditionSalePrice
0160RL65.08450PaveNaNRegLvlAllPubInsideGtlCollgCrNormNorm1Fam2Story7520032003GableCompShgVinylSdVinylSdBrkFace196.0GdTAPConcGdTANoGLQ706Unf0150856GasA...YSBrkr85685401710102131Gd8Typ0NaNAttchd2003.0RFn2548TATAY0610000NaNNaNNaN022008WDNormal208500
1220RL80.09600PaveNaNRegLvlAllPubFR2GtlVeenkerFeedrNorm1Fam1Story6819761976GableCompShgMetalSdMetalSdNone0.0TATACBlockGdTAGdALQ978Unf02841262GasA...YSBrkr1262001262012031TA6Typ1TAAttchd1976.0RFn2460TATAY29800000NaNNaNNaN052007WDNormal181500
2360RL68.011250PaveNaNIR1LvlAllPubInsideGtlCollgCrNormNorm1Fam2Story7520012002GableCompShgVinylSdVinylSdBrkFace162.0GdTAPConcGdTAMnGLQ486Unf0434920GasA...YSBrkr92086601786102131Gd6Typ1TAAttchd2001.0RFn2608TATAY0420000NaNNaNNaN092008WDNormal223500
3470RL60.09550PaveNaNIR1LvlAllPubCornerGtlCrawforNormNorm1Fam2Story7519151970GableCompShgWd SdngWd ShngNone0.0TATABrkTilTAGdNoALQ216Unf0540756GasA...YSBrkr96175601717101031Gd7Typ1GdDetchd1998.0Unf3642TATAY035272000NaNNaNNaN022006WDAbnorml140000
4560RL84.014260PaveNaNIR1LvlAllPubFR2GtlNoRidgeNormNorm1Fam2Story8520002000GableCompShgVinylSdVinylSdBrkFace350.0GdTAPConcGdTAAvGLQ655Unf04901145GasA...YSBrkr1145105302198102141Gd9Typ1TAAttchd2000.0RFn3836TATAY192840000NaNNaNNaN0122008WDNormal250000
......................................................................................................................................................................................................................................................
1455145660RL62.07917PaveNaNRegLvlAllPubInsideGtlGilbertNormNorm1Fam2Story6519992000GableCompShgVinylSdVinylSdNone0.0TATAPConcGdTANoUnf0Unf0953953GasA...YSBrkr95369401647002131TA7Typ1TAAttchd1999.0RFn2460TATAY0400000NaNNaNNaN082007WDNormal175000
1456145720RL85.013175PaveNaNRegLvlAllPubInsideGtlNWAmesNormNorm1Fam1Story6619781988GableCompShgPlywoodPlywoodStone119.0TATACBlockGdTANoALQ790Rec1635891542GasA...YSBrkr2073002073102031TA7Min12TAAttchd1978.0Unf2500TATAY34900000NaNMnPrvNaN022010WDNormal210000
1457145870RL66.09042PaveNaNRegLvlAllPubInsideGtlCrawforNormNorm1Fam2Story7919412006GableCompShgCemntBdCmentBdNone0.0ExGdStoneTAGdNoGLQ275Unf08771152GasA...YSBrkr1188115202340002041Gd9Typ2GdAttchd1941.0RFn1252TATAY0600000NaNGdPrvShed250052010WDNormal266500
1458145920RL68.09717PaveNaNRegLvlAllPubInsideGtlNAmesNormNorm1Fam1Story5619501996HipCompShgMetalSdMetalSdNone0.0TATACBlockTATAMnGLQ49Rec102901078GasA...YFuseA1078001078101021Gd5Typ0NaNAttchd1950.0Unf1240TATAY3660112000NaNNaNNaN042010WDNormal142125
1459146020RL75.09937PaveNaNRegLvlAllPubInsideGtlEdwardsNormNorm1Fam1Story5619651965GableCompShgHdBoardHdBoardNone0.0GdTACBlockTATANoBLQ830LwQ2901361256GasA...YSBrkr1256001256101131TA6Typ0NaNAttchd1965.0Fin1276TATAY736680000NaNNaNNaN062008WDNormal147500

1460 rows × 81 columns

  • 그 다음 확인해야 하는 것은 Numerical 변수와 Categorical 변수를 구분한다.
    • 먼저 numerical_features를 구분하자.
numeric_features = train.select_dtypes(include=[np.number])
print(numeric_features.columns)
print("The total number of numeric features are: ", len(numeric_features.columns))
Index(['Id', 'MSSubClass', 'LotFrontage', 'LotArea', 'OverallQual',
       'OverallCond', 'YearBuilt', 'YearRemodAdd', 'MasVnrArea', 'BsmtFinSF1',
       'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', '1stFlrSF', '2ndFlrSF',
       'LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath',
       'HalfBath', 'BedroomAbvGr', 'KitchenAbvGr', 'TotRmsAbvGrd',
       'Fireplaces', 'GarageYrBlt', 'GarageCars', 'GarageArea', 'WoodDeckSF',
       'OpenPorchSF', 'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea',
       'MiscVal', 'MoSold', 'YrSold', 'SalePrice'],
      dtype='object')
The total number of numeric features are:  38
  • numeric_features을 제외한 나머지 변수를 추출하자.
categorical_features = train.select_dtypes(exclude=[np.number])
print(categorical_features.columns)
print("The total number of numeric features are: ", len(categorical_features.columns))
Index(['MSZoning', 'Street', 'Alley', 'LotShape', 'LandContour', 'Utilities',
       'LotConfig', 'LandSlope', 'Neighborhood', 'Condition1', 'Condition2',
       'BldgType', 'HouseStyle', 'RoofStyle', 'RoofMatl', 'Exterior1st',
       'Exterior2nd', 'MasVnrType', 'ExterQual', 'ExterCond', 'Foundation',
       'BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2',
       'Heating', 'HeatingQC', 'CentralAir', 'Electrical', 'KitchenQual',
       'Functional', 'FireplaceQu', 'GarageType', 'GarageFinish', 'GarageQual',
       'GarageCond', 'PavedDrive', 'PoolQC', 'Fence', 'MiscFeature',
       'SaleType', 'SaleCondition'],
      dtype='object')
The total number of numeric features are:  43

IV. 연도 데이터 탐색 개요

  • 지난시간에 각 데이터에서 categorical_featuresnumeric_features를 각각 추출하는 방법에 대해 배웠다.

    • categorical_features: Alley, BldgType, BsmtCond, BsmtExposure, BsmtFinType1, BsmtFinType2, BsmtQual, CentralAir, Condition1, Condition2, Electrical, ExterCond, ExterQual, Exterior1st, Exterior2nd, Fence, FireplaceQu, Foundation, Functional, GarageCond, GarageFinish, GarageQual, GarageType, Heating, HeatingQC, HouseStyle, KitchenQual, LandContour, LandSlope, LotConfig, LotShape, MSZoning, MasVnrType, MiscFeature, Neighborhood, PavedDrive, PoolQC, RoofMatl, RoofStyle, SaleCondition, SaleType, Street, Utilitif
    • numeric_features:‘Id’, ‘MSSubClass’, ‘LotFrontage’, ‘LotArea’, ‘OverallQual’, ‘OverallCond’, ‘YearBuilt’, ‘YearRemodAdd’, ‘MasVnrArea’, ‘BsmtFinSF1’, ‘BsmtFinSF2’, ‘BsmtUnfSF’, ‘TotalBsmtSF’, ‘1stFlrSF’, ‘2ndFlrSF’, ‘LowQualFinSF’, ‘GrLivArea’, ‘BsmtFullBath’, ‘BsmtHalfBath’, ‘FullBath’, ‘HalfBath’, ‘BedroomAbvGr’, ‘KitchenAbvGr’, ‘TotRmsAbvGrd’, ‘Fireplaces’, ‘GarageYrBlt’, ‘GarageCars’, ‘GarageArea’, ‘WoodDeckSF’, ‘OpenPorchSF’, ‘EnclosedPorch’, ‘3SsnPorch’, ‘ScreenPorch’, ‘PoolArea’, ‘MiscVal’, ‘MoSold’, ‘YrSold’, ‘SalePrice’
  • 여기에서 우선 categorical_features는 논의에서 제외한다.

  • 이 중에서, 우선 numeric_features를 다시 살펴본다.

    • 우선 훈련데이터의 ID는 삭제한다.
    • 또한, 종속변수인 salesprice는 테스트 데이터에는 존재하지 않는다.
    • 그럼 결과적으로 36개numeric_features만 남게 된다.
  • 36개의 features만 남았다.

    • 여기에서 유심히 살펴보면 Year과 관련된 features가 보인다.
  • 특히 매출과 관련된 데이터를 다루는데 있어서, 연,월,일은 매우 중요하다. 패턴을 찾아서 특정 변수만 추출하는 코드가 필요하다.

    • YearBuilt, YearRemodAdd, GarageYrBlt, YrSold만 추출해보자.
year_fea = [fea for fea in numeric_features if 'Yr' in fea or 'Year' in fea]
print(year_fea)
['YearBuilt', 'YearRemodAdd', 'GarageYrBlt', 'YrSold']

(1) 연도의 변수 처리 방법

  • 여기에서 잊지 말아야 하는 것은 새로운 데이터셋을 만들더라도 항상 종속변수(sales price)는 늘 함께 움직여야 한다.
  • 각각의 변수는 어떻게 이해해야 할까?
    • 이 때, 필요한 것이 일종의 데이터 정의서가 필요하다.
    • data_description.txt를 참고하자.
  • 각 변수는 다음과 같다.
    • YearBuilt: Original construction date
    • YearRemodAdd: Remodel date (same as construction date if no remodeling or additions)
    • GarageYrBlt: Year garage was built
    • YrSold: Year Sold (YYYY)
  • 여기에서 우선 각 변수별로 연도가 차이가 나는지 확인해보자.
for fea in year_fea:
  data = train.copy()
  data[fea].value_counts(sort=False).plot(kind='bar')
  plt.xlabel(fea)
  plt.title(fea)
  plt.show()

png

png

png

png

  • 위 그래프를 보면서 알 수 있는 것은 무엇일까?
    • 우선, 첫 건축 시기는 1872년이고 첫 리모델링 시기는 1950년이고, 마지막으로 첫 차고 건축시기는 1930년으로 확인된다.
    • 그리고 매매 시기는 2006-2010년 사이로 집계된 것으로 확인할 수 있다.

(2) SalePrice와의 관계

  • 위 데이터는 각 연도의 특성을 이해하는데는 도움이 될지 모르지만, 결국 Kaggle대회에서 중요한 것은 종속변수와의 관계다
  • 조금 의미있는 변수를 만들어야 한다. (위 4가지 변수의 조합)
    • 보통 실무에서는 이를 도출변수라고 하는데.. 이 부분은 Intermediate level에서 조금 더 자세히 다루기로 한다.
    • 여기서 강사가 하고자 하는 것은 YrSold에서 그 외 다른 변수와의 연도 시기의 차이를 계산하면 통상적으로 연수가 짧으면 짧을수록 매매가도 올라가고 연수가 길면 길수록 매매가가 하락하는 것을 예상할 수 있다.
    • 실제 그러한 그래프를 그리도록 해보자.
for fea in year_fea:
    if fea!='YrSold': # `YrSold` 변수는 제외 한다.
        data=train.copy() # 이렇게 해주는 것이 좋다. (원본 데이터는 늘 보존할 수 있다)
        data[fea]=data['YrSold']-data[fea] #  여기가 사실 핵심 포인트다. 연수 차이 계산
        plt.scatter(data[fea], data['SalePrice']) # 산점도 그래프를 그린다.
        plt.title(fea)
        plt.xlabel(fea)
        plt.ylabel('SalePrice')
        plt.show()

png

png

png

  • 굳이 회귀선을 그리지 않더라도, 연수의 차이가 작을수록 매매가가 높게 형성된 것을 확인할 수 있다.

V. 양적 변수 시각화 - 이산형 그래프

VI. 양적 변수 시각화 - 연속형 그래프

  • 이번에는 수치형 변수중에서 연속형 그래프를 작성하려고 한다.
  • 먼저 가상 데이터를 생성해서 간단하게 SalePrice와 관련된 그래프는 어떻게 작성해야 하는지 확인해본다.

(1) 가상 데이터 생성

  • 먼저 가상 데이터를 생성해서 간단하게 SalePrice와 관련된 그래프는 어떻게 작성해야 하는지 확인해본다.
# discrete dataframe
LotArea = train['LotArea'].iloc[0:10]
temp = pd.DataFrame({'id' : [1,2,3,4,5,6,7,8,9,10],
                    'LotArea' : LotArea,
                    'SalePrice' : [1000,1300,2000,1030,2030,2050,2000,5000,3000,3500]
                    })
print(temp)
   id  LotArea  SalePrice
0   1     8450       1000
1   2     9600       1300
2   3    11250       2000
3   4     9550       1030
4   5    14260       2030
5   6    14115       2050
6   7    10084       2000
7   8    10382       5000
8   9     6120       3000
9  10     7420       3500

(2) 산점도 그래프

  • SalePriceLotArea 모두 연속형 변수이다. 이럴 때 보통 산점도 그래프를 그리는데, 산점도의 자세한 사항은 교재 설명을 참고한다.
  • 먼저 matplotlib 방식으로 산점도를 작성해본다.
plt.scatter(x=temp['LotArea'], y = temp['SalePrice'])
plt.show()

png

  • 그리고 seaborn 방식으로 산점도를 작성해보자.
sns.scatterplot(x='LotArea', y='SalePrice', data = temp)
plt.show()

png

(3) 실무 데이터 적용

  • 먼저 연속형 변수를 추출한다.
continuous_vars = [fea for fea in numeric_features if fea not in discrete_vars + year_fea + ['Id'] + ['SalePrice']]
print(continuous_vars)
print("The total number of continuous_vars are: ", len(continuous_vars))
['LotFrontage', 'LotArea', 'MasVnrArea', 'BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', '1stFlrSF', '2ndFlrSF', 'LowQualFinSF', 'GrLivArea', 'GarageArea', 'WoodDeckSF', 'OpenPorchSF', 'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'MiscVal']
The total number of continuous_vars are:  19
  • 이제 산점도를 작성한다.
fig, ax = plt.subplots(5, 4, figsize=(16, 10)) # 그래프의 행과 열 지정 및, 이미지 사이즈 지정
data = train.copy()

for i, col in enumerate(data[continuous_vars].columns[0:]): # 좌표 평면 지정
     if i <= 3:
        sns.scatterplot(x=data[col], y=data["SalePrice"], ax=ax[0,i]) # 1행 좌표 평면
     elif i <= 7:
        sns.scatterplot(x=data[col], y=data["SalePrice"], ax=ax[1,i-4]) # 2행 좌표 평면
     elif i <= 11:
        sns.scatterplot(x=data[col], y=data["SalePrice"], ax=ax[2,i-8]) # 3행 좌표 평면
     elif i <= 15:
        sns.scatterplot(x=data[col], y=data["SalePrice"], ax=ax[3,i-12]) # 4행 좌표 평면
     else: 
        sns.scatterplot(x=data[col], y=data["SalePrice"], ax=ax[4,i-16]) # 5행 좌표 평면

fig.suptitle('My Scatter Plots')
fig.tight_layout()
fig.subplots_adjust(top=0.95)

png

  • 위 소스코드는 전체 continous var의 19개 변수를 각각 그래프 상에 뿌려주도록 한 것이다.
  • 그런데, 0이라고 표현된 것이 있다 특히 PoolArea와 같은 변수들인데, 이러한 데이터는 어떻게 처리하는 것이 나을까?
    • 보통 실무에서는 이러한 데이터를 만나면 연속형 변수를 범주형(categorical) 변수로 재범주화 하는 것이 타당하다. (예: zero and over 400)
    • 다만, 이러한 부분은 통계분석 또는 머신러닝을 할 때는 이렇게 연속형 변수를 범주화 해서 진행하는 것도 대안으로 생각할 수 있다.

VI. Review & What’s next

  • 처음 프로그래밍을 입문하시는 분들에게 for-loop 또는 if 문법에 대해 고민하지 말 것을 권한다.
    • 우선 intermediate 들어가기전에 그래프의 종류, 기초 문법, 데이터 타입의 종류 등에 대해 한번 정리를 할 것이다.
  • 연속형 그래프의 핵심은 여러 그래프를 한 이미지로 확인할 수 있도록 구현하기 위해 그래프의 좌표평면 기법을 도입했다는 것을 확인한다.
  • 범주형 그래프와 관련된 그래프는 이산형 그래프와 방식은 유사하지만, 주요 feature를 확인하기 그래프는 어떤 것이 좋을지 나누도록 하겠다.