본문 바로가기

머신러닝&딥러닝

머신러닝&딥러닝 (2) - 선형회귀

2023.06.09 수업내용

 

1. 선형회귀

1. Rent 데이터셋 살펴보기

불러오기

import numpy as np
import pandas as pd
import seaborn as sns
rent_df = pd.read_csv('/content/drive/MyDrive/KDT/머신러닝&딥러닝/rent.csv')
rent_df

rent_df.info()

  • 0 부터 4745번의 index를 가진 4746개의 data가 존재
  • 총 columns는 12개
  • BHK, Size 에서 결측치를 나타내고 있음
  • Dtype은 float, int, object 3 가지 종류가 있음

컬럼 정리

  • Posted On : 매물 등록 날짜
  • BHK : 베드, 홀, 키친의 개수
  • Rent : 렌트비
  • Size : 집 크기
  • Floor : 총 층수 중 몇 층
  • Area Type : 공용공간을 포함하는지, 집의 면적만 포함하는지
  • Area Locality : 지역
  • City : 도시
  • Furnishing Status : 풀옵션 여부
  • Tenant Preferred : 선호하는 가족 형태
  • Bathroom : 화장실 개수
  • Point of Contact : 연락할 곳
rent_df.describe()

* Rent의 값이 지수적으로 나타남

round(rent_df.describe(), 2)

  • 소수점 둘째 자리까지 반올림
  • round를 통해 통계량을 반올림
sns.displot(rent_df['BHK'])

sns.displot(rent_df['Rent'])

* 3,500,000 내외의 Rent가 존재함을 알 수 있음

rent_df['Rent'].sort_values()

  • 실재로 3,500,000 이 존재함을 확인
  • 이상치 인지를 확인하는 작업을 진행
sns.boxplot(y=rent_df['Rent'])

rent_df.isna().sum()

rent_df.isna().mean()

rent_df.dropna(subset=['Size'])
  • subset은 dropna()의 매개변수
  • Size에 있는 결측치 데이터를 삭제
rent_df[rent_df['Size].isna()]

* rent_df 데이터프레임에서 Size 컬럼이 NaN인 행을 모두 출력

na_index = rent_df[rent_df['Size'].isna()].index
na_index

rent_df.iloc[na_index]

 

결측치 처리

1. 결측 데이터가 전체 데이터에 비해 양이 굉장히 적을 경우 삭제하는 것도 방법

2. 결측치에 데이터를 채울 경우 먼저 boxplot을 확인하는 것이 좋음

sns.boxplot(y = rent_df['Size'])

  • boxplot을 확인 후 mean 보다는 median을 사용하는게 좋다고 판단
  • 큰 이상치는 없다고 판단하였지만 분포의 비대칭성이 크다고 판단하여 중앙값을 사용하는 것이 평균보다 적절하다고 생각함
rent_df.fillna(rent_df.median()).loc[na_index]

 

* 마찬가지로 BHK도 똑같이 결측치 제거 작업

na_index = rent_df[rent_df['BHK'].isna()].index
na_index

sns.boxplot(y = rent_df['BHK'])
rent_df['BHK'].fillna(rent_df['BHK'].median()).loc[na_index]

rent_df = rent_df.fillna(rent_df.median())
  • BHK의 경우 int 값이므로 mean(float)보다는 median(int)로 결측치를 제거하는 것이 좋음
rent_df.info()

결측치가 모두 제거된 것을 확인할 수 있음

rent_df['Area Type'].value.counts()

또는 unique를 사용할 수 있음

rent_df['Area Type'].unique()
rent_df['Area Type'].nunique()

  • unique는 컬럼 값의 목록을 알 수 있음
  • nunique는 목록의 개수를 알 수 있음
for i in ['Floor', 'Area Type', 'Area Locality', 'City', 'Furnishing Status', 'Tenant Preferred', 'Point of Contact']:
    print(i, rent_df[i].nunique())

  • Rent 값에 대한 영향을 미치는 요인을 파악하는 프로젝트라 가정한다면
  • 'Posted On', 'Floor', 'Area Locality', 'Tenant Preferred', 'Point of Contact' 는 영향을 미치기 어렵다고 판단
  • Floor의 경우 다음번의 데이터정리에서 다시 다루기 위해 배제함
rent_df.drop(['Posted On', 'Floor', 'Area Locality', 'Tenant Preferred', 'Point of Contact'], axis = 1, inplace = True)
rent_df.info()

* object 형태의 Area Type, City, Furnishing Status를 원 핫 인코딩으로 변환

rent_df = pd.get_dummies(rent_df, columns = ['Area Type', 'City', 'Furnishing Status'])
rent_df

* 데이터를 독립변수와 종속변수로 나눔

X = rent_df.drop('Rent', axis = 1)  # 독립변수
y = rent_df['Rent']  # 종속변수
  • 다른 요소 : X => 독립변수
  • Rent : y => 종속변수

불러오기

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,
                                                                             y,
                                                                             test_size=0.2,
                                                                             random_state=10)
X_train.shape, X_test.shape

y_train.shape, y_test.shape

 

 

2. 선형 회귀(Linear Regression)

  • 데이터를 통해 가장 잘 설명할 수 있는 직선으로 데이터를 분석하는 방법
  • 단순 선형 회귀 분석(단일 독립변수를 이용)
  • 다중 선형 회귀 분석(다중 독립변수를 이용)
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(X_train, y_train)
pred = lr.predict(X_test)
pred

* 사진 상 데이터 생략

 

3. 평가 지표 만들기

3-1. MSE(Mean Squared Error)

  • 예측값과 실제값의 차이에 대한 제곱에 대해 평균을 낸 값
  • 제곱을 통해 오차의 음수를 제거

p = np.array([3, 4, 5])  # 예측값
act = np.array([1, 2, 3])  # 실제값
def my_mse(pred, actual):
    return ((pred - actual) ** 2).mean()
my_mse(p, act)

3-2. MAE(Mean Absolute Error)

  • 예측값과 실제값의 차이에 대한 절대값에 대해 평균을 낸 값
  • 역전파에서 절대값은 미분이 되지 않기 때문에 딥러닝이나 머신러닝에서는 잘 쓰이지 않는다

def my_mae(pred, actual):
    return np.abs(pred - actual).mean()
my_mae(p, act)

* 입력 - 히든(연산) - 출력 : 순전파

* 반대의 경우 역전파라고 함. 이때 역전파에서 미분으로 기울기를 구함

 

3-3. RMSE(Root Mean Squared Error)

  • 예측값과 실제값의 차이에 대한 제곱에 대해 평균을 낸 후 루트를 씌운 값

def my_rmse(pred, actual):
    return np.sqrt(my_mse(pred - actual))
my_rmse(p, act)

불러오기

from sklearn.metrics import mean_absolute_error, mean_squared_error
mean_absolution_error(p, act) # MAE
mean_squared_error(p, act) # MSE
mean_absolution_error(p, act, squared = False) # RMSE

3-4. 평가 지표 적용하기

mean_squared_error(y_test, pred)
mean_absolute_error(y_test, pred)
mean_squared_error(y_test, pred, squared = False)

* 이상치 제거 (1837번)

X_train.drop(1837, inplace = True)
y_train.drop(1837, inplace = True)
lr.fit(X_train, y_train)
pred = lr.predict(X_test)
mean_squared_error(y_test, pred, squared = False)

  • 이상치를 제거 전, 후 비교

 

4. 로그 활용하기

a = [1, 2, 3, 4, 5]
b = [1, 10, 100, 1000, 10000]
sns.lineplot(x=a, y=b)

b_log = np.log(b)
b_log

np.exp(b_log)

y_train_log = np.log(y_train)
lr.fit(X_train, y_train_log)
pred = lr.predict(X_test)
mean_squared_error(y_test, pred, squared = False)

  • 1837 데이터를 삭제하기전 RMSE : 41438.940
  • 1837 데이터를 삭제한 후  RMSE : 41377.570
  • log를 활용하여 비선형으로 변경한 후 RMSE : 70418.553

log를 이용하여 곡선으로 만들었을 때, 오차가 커짐 => 데이터가 곡선보다는 선형

데이터의 분포가 비선형일 때, 로그를 사용하는 것이 오차가 적으며, 선형일 때 로그를 사용하지 않는 것이 오차가 적음