Data Analysis/Kaggle 코드리뷰

[Kaggle] House Prices - Advanced Regression Techniques

알밤바 2022. 6. 30. 11:11
728x90
반응형


목차

1. Import Library & Data
2. Analysing 'SalePrice'
3. SalePrice's relationship
   3.1 Relationship with numeric variables
   3.2 Relationship with categorical variables
4. SalePrice's Correlation
   4.1 Correlation matrix (heatmap style)
   4.2 'SalePrice' correlation matrix (zoomed heatmap style)
   4.3 Scatter plot between 'SalePrice' and correlated variables
5. Missing data
6. Outlier (이상치)
   6.1 Univariate analysis (일변량 분석)
   6.2 Bivariate analysis (이변량분석)
7. normality (정규성)
8. homoscedasticity(등분산성)
9. Dummy variables (더미 변수)


1. Import Library & Data

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy.stats import norm
from sklearn.preprocessing import StandardScaler
from scipy import stats
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline

 

#bring in the six packs
df_train = pd.read_csv('../input/train.csv')

 

df_train.columns

Index(['Id', 'MSSubClass', 'MSZoning', 'LotFrontage', 'LotArea', 'Street',
       'Alley', 'LotShape', 'LandContour', 'Utilities', 'LotConfig',
       'LandSlope', 'Neighborhood', 'Condition1', 'Condition2', 'BldgType',
       'HouseStyle', 'OverallQual', 'OverallCond', 'YearBuilt', 'YearRemodAdd',
       'RoofStyle', 'RoofMatl', 'Exterior1st', 'Exterior2nd', 'MasVnrType',
       'MasVnrArea', 'ExterQual', 'ExterCond', 'Foundation', 'BsmtQual',
       'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinSF1',
       'BsmtFinType2', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', 'Heating',
       'HeatingQC', 'CentralAir', 'Electrical', '1stFlrSF', '2ndFlrSF',
       'LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath',
       'HalfBath', 'BedroomAbvGr', 'KitchenAbvGr', 'KitchenQual',
       'TotRmsAbvGrd', 'Functional', 'Fireplaces', 'FireplaceQu', 'GarageType',
       'GarageYrBlt', 'GarageFinish', 'GarageCars', 'GarageArea', 'GarageQual',
       'GarageCond', 'PavedDrive', 'WoodDeckSF', 'OpenPorchSF',
       'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'PoolQC',
       'Fence', 'MiscFeature', 'MiscVal', 'MoSold', 'YrSold', 'SaleType',
       'SaleCondition', 'SalePrice'],
      dtype='object')

 

 

2. Analysing 'SalePrice'

1) SalePrice의 통계적 요약 확인

df_train['SalePrice'].describe()

count      1460.000000
mean     180921.195890
std       79442.502883
min       34900.000000
25%      129975.000000
50%      163000.000000
75%      214000.000000
max      755000.000000
Name: SalePrice, dtype: float64

 

2) SalePrice의 분포를 히스토그램으로 파악

# histogram
sns.distplot(df_train['SalePrice'])

→ 정규 분포에서 벗어난다.

→ 양의 왜도이다.

→ 절정을 보여준다.

 

3) 왜도와 첨도 수치 확인

#skewness and kurtosis
print("Skewness: %f" % df_train['SalePrice'].skew())
print("Kurtosis: %f" % df_train['SalePrice'].kurt())

Skewness: 1.882876
Kurtosis: 6.536282

 

3. SalePrice's relationship

3.1 Relationship with numeric variables (숫자형 변수)

1) GrLivArea (지상 거주 면적 평방 피트)

#scatter plot grlivarea/saleprice
var = 'GrLivArea'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000));

→ SalePrice와 GrLivArea는 선형 관계를 보인다.

 

2) TotalBsmtSF (지하 면적의 총 평방 피트)

#scatter plot totalbsmtsf/saleprice
var = 'TotalBsmtSF'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000));

→ SalePrice와 TotalBsmtSF는 강한 선형 관계를 보인다.

 

3.2 Relationship with categorical variables (범주형 변수)

1) OverallQual (전반적인 집의 품질)

→ 1: very poor ~ 10: very Excellent

 

#box plot overallqual/saleprice
var = 'OverallQual'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
f, ax = plt.subplots(figsize=(8, 6))
fig = sns.boxplot(x=var, y="SalePrice", data=data)
fig.axis(ymin=0, ymax=800000);

→ 품질이 좋을수록 (숫자가 높을수록) 가격이 높은 것을 확인할 수 있다.

 

2) YearBuilt (집이 지어진 연도)

var = 'YearBuilt'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
f, ax = plt.subplots(figsize=(16, 8))
fig = sns.boxplot(x=var, y="SalePrice", data=data)
fig.axis(ymin=0, ymax=800000);
plt.xticks(rotation=90);

큰 경향을 띄지는 않지만 'SalePrice'가 오래된 집보다는 새로운 집이 더 비싸다는 것을 확인할 수 있다.

 

4. SalePrice's Correlation

4.1 Correlation matrix (heatmap style)

#correlation matrix
corrmat = df_train.corr()
f, ax = plt.subplots(figsize=(12, 9))
sns.heatmap(corrmat, vmax=.8, square=True);

히트맵은 컬럼들의 관계를 빠르게 파악할 수 있는 가장 좋은 방법이다.

히트맵을 살펴보면, 다음과 같다.

→ 'TotalBsmtSF' & '1stFlrSF' , 'GarageCars' & 'GarageArea' : 서로 간에 상관관계가 높음 (다중공산성)

→ 'SalePrice' - 'GrLivArea', 'TotalBsmtSF', 'OverallQual' : 상관관계가 높음 (그 외에도 봐야할 변수들이 있음)

 

4.2 'SalePrice' correlation matrix (zoomed heatmap style)

✔ 'SalePrice'와 가장 상관관계가 높은 변수 10개를 추출하여 히트맵으로 나타냄

.nlargest(n, columns, keep = 'first')
✔ 데이터를 오름차순 정렬 후 위에서 n개의 행을 출력하는 메서드
df.sort_values(columns,  ascending = True)와 사용방식이 동일함
- n : 정렬 후 출력할 값의 개수
- columns : 정렬의 기준이 될 열
- keep = {first, last, all} : 동일한 값일 경우, 어느 행을 출력할 지 선택 (first : 위부터, last : 아래부터, all : 전체)

+) nsmallest 메서드는 데이터를 내림차순 정렬 후 위에서 n개의 행을 출력하는 메서드임

 

#saleprice correlation matrix
k = 10 #number of variables for heatmap
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(df_train[cols].values.T)
sns.set(font_scale=1.25)
hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f', annot_kws={'size': 10}, yticklabels=cols.values, xticklabels=cols.values)
plt.show()

'GrLivArea', 'TotalBsmtSF', 'OverallQual' : 상관관계가 높음

'GarageCars', 'GarageArea' : 다중공산성을 띄기에 변수 하나 제거 ('GarageCars' 유지)

'TotalBsmtSF', '1stFloor' : 다중공산성을 띔

'FullBath'

'TotRmsAbvGrd', 'GrLivArea' : 다중공산성을 띔

'YearBuilt' : 시계열 분석이 필요함

 

4.3 Scatter plot between 'SalePrice' and correlated variavles

#scatterplot
sns.set()
cols = ['SalePrice', 'OverallQual', 'GrLivArea', 'GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']
sns.pairplot(df_train[cols], size = 2.5)
plt.show();

✔ 'TotalBsmtSF', 'GrLiveArea' : 선형 관계를 뜸 (가장자리에 선형으로 나타남)

     → 지하실은 윗층 공간과 동일할 수 있으나 지하실이 윗층보다 더 크진 않을 것임

 

5. Missing data

1. 결측치가 얼마나 퍼져있는가?
2. 결측치가 랜덤인지, 패턴이 있는가?

 

#missing data

# sort_values 메서드는 값을 기준으로 레이블을 정렬하는 메서드
total = df_train.isnull().sum().sort_values(ascending=False)  
percent = (df_train.isnull().sum()/df_train.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
missing_data.head(20)

✔  'PoolQC', 'MiscFeature', 'Alley' : 결측치가 많으므로 제거 필요

✔ 'GarageCond', 'GarageType', 'GarageYrBlt', 'GarageFinish', 'GarageQual' : 결측치 수가 동일함 / 'Garage' 변수 모두 제거 필요

✔ 'BsmtExposure', 'BsmtFinType2', 'BsmtFinType1', 'TsmtCond', 'TsmtQual' : 결측치 수가 동일함 / 'Tsmt' 변수 모두 제거 필요

 'MasVnrArea', 'MasVnrType' : 'YearBuilt', 'OverallQual'와 강한 상관관계가 있는 것을 이미 확인 → 제거 필요

 'Electrical' : 결측치가 1개이기에 결측치를 제거하되 변수를 유지

 

#dealing with missing data
# 결측치의 수가 1 이상인 데이터 제거
df_train = df_train.drop((missing_data[missing_data['Total'] > 1]).index,1)
# 'Electrical' 변수에서 null값인 데이터만 제거
df_train = df_train.drop(df_train.loc[df_train['Electrical'].isnull()].index)
df_train.isnull().sum().max() #just checking that there's no missing data missing...

0

 

6. Outlier (이상치)

6.1 Univariate analysis (일변량 분석)

우리는 데이터를 표준화(Standardization)해야 한다.

데이터 표준화는 평균이 0이고 표준편차가 1이 되도록 변환하는 것을 의미함

변수들 간 척도가 다른 경우, 데이터 표준화를 함

 

#standardizing data
saleprice_scaled = StandardScaler().fit_transform(df_train['SalePrice'][:,np.newaxis]);
low_range = saleprice_scaled[saleprice_scaled[:,0].argsort()][:10]
high_range= saleprice_scaled[saleprice_scaled[:,0].argsort()][-10:]
print('outer range (low) of the distribution:')
print(low_range)
print('\nouter range (high) of the distribution:')
print(high_range)

outer range (low) of the distribution:
[[-1.83820775]
 [-1.83303414]
 [-1.80044422]
 [-1.78282123]
 [-1.77400974]
 [-1.62295562]
 [-1.6166617 ]
 [-1.58519209]
 [-1.58519209]
 [-1.57269236]]

outer range (high) of the distribution:
[[3.82758058]
 [4.0395221 ]
 [4.49473628]
 [4.70872962]
 [4.728631  ]
 [5.06034585]
 [5.42191907]
 [5.58987866]
 [7.10041987]
 [7.22629831]]

 

→ Low range : 0에 가깝거니 멀지 않음

→ High range : 0에서 7까지의 범위이고 몇몇 값은 그 이상임

→ 이 중에서 7.x인 이상치 2개는 주의할 필요가 있음

 

6.2 Bivariate analysis (이변량분석)

- 이변량 분석 : 두 개의 변수만이 포함되는 통계적 분석

 

우리는 이미 산점도를 그려보았지만, '이상치'에 초점을 맞추어 다시 확인해보자.

 

#bivariate analysis saleprice/grlivarea
var = 'GrLivArea'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000));

✔ 빨간색 박스 값 2개

    : 'GrLivArea'에서 유독 큰 값이 있음.

      아마 농업지역으로 추론이 되며 그렇기에 면적이 넓은 것에 비해 값이 낮은 거라 생각됨

      이 값들은 전형적인 경우를 대표하지 않는다고 판단이 되어 제거하고자 함

 

✔ 분홍색 박스 값 2개

    : 이것은 위에서 확인하였던 7.x 값 2개임

      특이하게 값이 크지만, 전반적인 경향을 따르기 때문에 제거하지 않고 유지하고자 함

 

#deleting points (빨간색 박스 값 2개 제거)
df_train.sort_values(by = 'GrLivArea', ascending = False)[:2]
df_train = df_train.drop(df_train[df_train['Id'] == 1299].index)
df_train = df_train.drop(df_train[df_train['Id'] == 524].index)

 

#bivariate analysis saleprice/grlivarea
var = 'TotalBsmtSF'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000));

→ 'TotalBsmtSF'가 3000이상인 데이터를 제거하고 싶을 수는 있지만,

    이상치라고 판단하지 않고 제거하지 않을 예정

 

7. normality (정규성)

📌정규화(normalization)

- 값들을 0과 1 사이의 범위로 이동하고 재조정시키는 스케일링 기법

- min-max scaling이라고도 하며, python의 경우 minmaxscaler로 간단하게 구현이 가능함

출처 : https://heeya-stupidbutstudying.tistory.com/32

[링크1] Normalization vs Standardization

[링크2] Normalization vs Standardization

 

7.1 SalePrice

히스토그램(Histogram) : 첨도와 왜도 확인

정규분포도(Normal probability plot) : 데이터 분포가 정규 분포를 나타내는 대각선과 유사해야 함

 

#histogram and normal probability plot
sns.distplot(df_train['SalePrice'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['SalePrice'], plot=plt)

✔ 양의 왜도를 띄며 대각선을 따르지 않는 것을 확인할 수 있음

✔ 한쪽으로 치우치며 양의 왜도를 띄기 때문에 로그 변환을 해주어야 함

 

#applying log transformation
df_train['SalePrice'] = np.log(df_train['SalePrice'])

 

#transformed histogram and normal probability plot
sns.distplot(df_train['SalePrice'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['SalePrice'], plot=plt)

 

7.2 GrLivArea

#histogram and normal probability plot
sns.distplot(df_train['GrLivArea'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['GrLivArea'], plot=plt)

 

'GrLivArea' 또한 양의 왜도를 띄고 있기에 로그 변환을 해주자.

 

#data transformation
df_train['GrLivArea'] = np.log(df_train['GrLivArea'])

 

#transformed histogram and normal probability plot
sns.distplot(df_train['GrLivArea'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['GrLivArea'], plot=plt)

 

7.3 TotalBsmtSF

#histogram and normal probability plot
sns.distplot(df_train['TotalBsmtSF'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['TotalBsmtSF'], plot=plt)

✔ 상당한 수의 값들이 0임 (지하가 없는 집)

✔ 값이 0인 경우에는 로그 변환을 수행할 수 없음

→ 그렇기에 우리는 '지하가 있음', '지하가 없음'으로 변수를 만들 수 있음. (이진변수)

     그런 후 0이 아닌 관측치에 대해 로그 변환을 진행

     이 방법으로 지하의 존재 여부와 상관없이 데이터를 변환할 수 있음

 

#create column for new variable (one is enough because it's a binary categorical feature)
#if area>0 it gets 1, for area==0 it gets 0
df_train['HasBsmt'] = pd.Series(len(df_train['TotalBsmtSF']), index=df_train.index)
df_train['HasBsmt'] = 0 
df_train.loc[df_train['TotalBsmtSF']>0,'HasBsmt'] = 1

 

#transform data
df_train.loc[df_train['HasBsmt']==1,'TotalBsmtSF'] = np.log(df_train['TotalBsmtSF'])

 

#histogram and normal probability plot
sns.distplot(df_train[df_train['TotalBsmtSF']>0]['TotalBsmtSF'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train[df_train['TotalBsmtSF']>0]['TotalBsmtSF'], plot=plt)

 

8. homoscedasticity(등분산성)

등분산성
- 분석하는 집단들의 분산이 같음을 나타냄
- 반드시 정규성이 있어야 함

2개의 변수에 대한 등분산성을 검정하는 가장 좋은 방법은 그래프로 확인하는 것이다.

 

8.1 GrLivArea - SalePrice

#scatter plot
plt.scatter(df_train['GrLivArea'], df_train['SalePrice']);

✔ 로그 변환 이전의 산점도는 원뿔모양이었음

✔ 로그 변환 이후의 현재 산점도는 원뿔모양이지 않고 정규성을 띔

✔ 정규성을 띄기에 등분산성 문제는 해결되었음

 

8.2 TotalBsmtSF - SalePrice

#scatter plot
plt.scatter(df_train[df_train['TotalBsmtSF']>0]['TotalBsmtSF'], df_train[df_train['TotalBsmtSF']>0]['SalePrice']);

✔ 'SalePrice'는 'TotalBsmtSF' 범위에 걸쳐 동일한 수준으로 변하는 것을 확인할 수 있음

 

9. Dummy variables (더미 변수)

#convert categorical variable into dummy
df_train = pd.get_dummies(df_train)

 

728x90
반응형