책/파이썬 데이터과학통계학습(23.01.03-23.01.09)(정보문화사)

part03회귀(05~07)

정지홍 2023. 1. 7. 22:15

선형 회귀분석

회귀분석은 연속형 종속변수 1개와 1개 이상의 범주형/연속형 독립변수 간 관계를 분석

 

-단순선형회귀: 종속변수1개 , 독립변수1개

-다중선형회귀: 종속변수1개 , 독립변수2개

 

회귀모형은 인과관계를 말하지 않으며 인과관계가 있다는 것을 전제로 한다. 이것을 바탕으로 관계의 정도 및 불확실성 정도 등을 파악한다.


단순선형회귀의 미지의 직선관계를 Y=a+bx+e라하자 여기서 e는 N(0,분산)인 오차항을 나타낸다

기본적으로 다음 가정을 한다.

-선형성

-독립성

-등분산성

-정규성

회귀계수를 측정하기 위하여 최소제곱법을 사용하며 이를 통해 얻은 것을 통하여 실측값과 회귀선 위의 값(예측값)의 차이를 잔차라고 하며 이것이 작을수록 좋다.

 

유의성검정

-모형 유의성-->기울기가 0인지 검정

-계수 유의성-->각 계수 값이 0인지 검정


import numpy as np
import pandas as pd
from scipy import stats
import statsmodels.api as sm
from statsmodels.formula.api import ols
import sklearn.linear_model
from sklearn.model_selection import train_test_split
from matplotlib import pyplot as plt
import seaborn as sns
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')

df=pd.read_csv('./data/regression/kc_house_data.csv')
df.index+=1
df


#결측치가 있는지 확인
df.isnull().sum()

 
Out[5]:
id               0
date             0
price            0
bedrooms         0
bathrooms        0
sqft_living      0
sqft_lot         0
floors           0
waterfront       0
view             0
condition        0
grade            0
sqft_above       0
sqft_basement    0
yr_built         0
yr_renovated     0
zipcode          0
lat              0
long             0
sqft_living15    0
sqft_lot15       0
dtype: int64

df_stats=df.describe().T
skew_results = []
kurtosis_results = []
null_results = []
median_results = []

for idx, val in enumerate(df_stats.index):
    median_results.append(df[val].median())
    skew_results.append(df[val].skew())
    kurtosis_results.append(df[val].kurtosis())
    null_results.append(df[val].isnull().sum())  

df_stats['median'] = median_results
df_stats['missing'] = null_results
df_stats['skewness'] = skew_results
df_stats['kurtosis'] = kurtosis_results
df_stats


print("위를 보면 price의 왜도가 4.02로 왼쪽으로 치우쳐저 있음을 알 수 있다.")
print("이를 자연로그를 이용하여 분포를 조정할 필요가 있다.")
df['price'].hist()

위를 보면 price의 왜도가 4.02로 왼쪽으로 치우쳐저 있음을 알 수 있다.
이를 자연로그를 이용하여 분포를 조정할 필요가 있다.
Out[9]:
<AxesSubplot: >

print("자연로그 이용")
np.log(df['price']).hist()

자연로그 이용
Out[10]:
<AxesSubplot: >

np.log(df['price']).skew()

0.42807247557592526

 


def separeate_dtype(df):
    df_obj=df.select_dtypes(include=['object'])
    df_numr=df.select_dtypes(include=['int64','float64'])
    return [df_obj,df_numr]

(df_obj,df_numr)=separeate_dtype(df)
df_obj.head()

date12345

20141013T000000
20141209T000000
20150225T000000
20141209T000000
20150218T000000

print("data에서 앞에 년도부분인 4자리만 추출하고 이걸 date2에 저장")
df_obj['date2'] = df_obj['date'].apply(lambda x: x[0:4])
df['date2'] = df_obj['date2'].astype('int64')
df['date2']
data에서 앞에 년도부분인 4자리만 추출하고 이걸 date2에 저장
Out[20]:
1        2014
2        2014
3        2015
4        2014
5        2015
         ... 
21609    2014
21610    2015
21611    2014
21612    2015
21613    2014
Name: date2, Length: 21613, dtype: int6

print("집이 매각된 연도인 date2와 지어진 년도인 yr_built의 차이를 구하여 추가")
df['sold-built_years'] = df.apply(lambda x: ((x['date2']) - (x['yr_built'])), axis=1)
df['sold-built_years']

집이 매각된 연도인 date2와 지어진 년도인 yr_built의 차이를 구하여 추가
Out[21]:
1        59
2        63
3        82
4        49
5        28
         ..
21609     5
21610     1
21611     5
21612    11
21613     6
Name: sold-built_years, Length: 21613, dtype: int64

print("독립변수 데이터의 분포를 확인")
df.hist(figsize=(22,18),density=True)
plt.show()


print("종속변수인 가격과 선형관계가 있을 것 같은 독립변수(집값에 영향을 미칠 것 같은 것들)들을 뽑아서 산점도를 그린다.")
df_pairplot = df[['price','bedrooms','sqft_living', 'waterfront', 'view', 'yr_built','sold-built_years','date2']]
sns.pairplot(df_pairplot)
plt.show()

종속변수인 가격과 선형관계가 있을 것 같은 독립변수(집값에 영향을 미칠 것 같은 것들)들을 뽑아서 산점도를 그린다.

 
 
print("종속변수 가격과 독립 변수인 거실면적간의 선형관계를 파악할 수 있다.")
print("다음은 히트맵을 통하여 살펴본다.")
df_corr = df.corr()
cmap = sns.diverging_palette(240, 10, n=9, as_cmap=True)

mask = np.zeros_like(df_corr, dtype=np.bool)
mask[np.triu_indices_from(mask)] = True

plt.figure(figsize=(16,12))

sns.heatmap(df.corr(), annot=True, mask=mask, cmap=cmap, linewidths=.5, fmt = '.2f', annot_kws={"size":10})
 
 
종속변수 가격과 독립 변수인 거실면적간의 선형관계를 파악할 수 있다.
다음은 히트맵을 통하여 살펴본다.
Out[25]:
<AxesSubplot: >

print("아래표를 통하여 거실너비, 나머지너비가 상관관계가 높다")
df_corr.sort_values(by='price', ascending=False)[['price']]


living = df[['sqft_living','sqft_living15','sqft_above']]

plt.figure(figsize=(12,6))

ax = sns.distplot(df['sqft_living'], hist=True, norm_hist=False, kde=False, label="sqft_living", color = 'blue')
ax = sns.distplot(df['sqft_living15'], hist=True, norm_hist=False, kde=False, label="sqft_living15", color = 'green')
ax = sns.distplot(df['sqft_above'], hist=True, norm_hist=False, kde=False, label="sqft_above", color = 'red')
ax.set(xlabel="sqft_living / sqft_living15 / sqft_above")

plt.legend()
plt.show()


print("단순선형회귀분석으로 상관관계가 가장 높은 거실 면적을 이용")
sns.jointplot(x='sqft_living', y='price', data=df, kind='reg')
plt.show()

단순선형회귀분석으로 상관관계가 가장 높은 거실 면적을 이용

X = df[['sqft_living']]
y = df[['price']]

X = sm.add_constant(X, has_constant="add")
X.head()

constsqft_living12345

1.0 1180
1.0 2570
1.0 770
1.0 1960
1.0 1680

model = sm.OLS(y, X)
result_model = model.fit()
result_model.summary()


result_model.resid.plot()
plt.show()


회귀모형의 가정진단

-회귀모형은 반응 변수와 설명 변수의 선형 관계를 전제로 한다.

-오차에 관하여 독립성,정규성,등분산성 가정을 전제로 한다.

 


선형성의 진단 방법

-산점도

-상관계수

 

만약 선형성을 만족x------>변수 변환으로 선형성을 유도한다---->이렇게 하여 선형 관계로 표현 가능시 선형모형이라 할 수있다.


오차의 독립성문제는 관측치가 서로 상관 되어 있으면 발생

 

독립성의 진단 방법

-Durbin-Watson

-Auto Correlation Function

-잔차 그래프


등분산성의 진단 방법

-잔차 등분산 그래프

-white test


정규성의 진단방법

-첨도와 왜도

-Q-Q plot

-정규성 검정

 

q=sm.qqplot(result_model_2.resid , line="s")


print("잔차 패턴 확인")
fitted=result_model_2.predict()

resid=result_model_2.resid
pred=result_model_2.predict(X)
fig=plt.scatter(pred,resid,s=3)
plt.xlabel('fitted values')
plt.ylabel('residual')
잔차 패턴 확인
Text(0, 0.5, 'residual'


result_shapiro = stats.shapiro(result_model_2.resid)
print(f'F value : {result_shapiro[0]:.4f} / p-value : {result_shapiro[1]:.4f}')
 
if result_shapiro[1] < 0.05:
    print("p-value < 0.05 입니다.")
F value : 0.9959 / p-value : 0.0000 p-value < 0.05 입니다.

 

result_model_2.resid.plot()
plt.show()
 


print("acf를 이용하여 독립성 만족 여부를 확인, 아래에서 0시차후에 파란색 구간을 벗어나는 시차가 없기 때문")
sm.graphics.tsa.plot_acf(result_model_2.resid)
plt.show()
acf를 이용하여 독립성 만족 여부를 확인, 아래에서 0시차후에 파란색 구간을 벗어나는 시차가 없기 때문
 


sns.distplot(result_model_2.resid)
plt.show()


result_model_2.resid.plot()
plt.show()