파이썬 프로그래밍으로 이해하는 선형회귀 원리

2019-04-27

Data_Engineering_TIL_(20190427)

study program : https://www.fastcampus.co.kr/extension_des

[학습목표]

  • Linear Regression 원리 이해

[학습기록]

  • 집의 넓이 데이터로 부동산 가격을 예측 하는 Linear Regression을 구현해보자

30평 = 3억 4천만원

50평 = 5억 6천만원

10평 = 1억 4천만원

일때 x평일때 가격은?

  • Linear Regression 수식 정립

1

  • Cost Function

어떤가정 h를 세웠을때, 그 가정이 얼마나 틀렸는가를 비용으로 간주하여 수식을 세움

이렇게 정의한 비용을 최소화하는 방향을 파라미터들을 조정하면 좀 더 올바른 가정 h를 가질 수 있다.

이번 예시에서 비용함수는 아래와 같다.

파라미터가 세타0, 세타1인 비용함수이다.

아래 비용함수 수식에서 1/2m은 계산상 편의를 위해, 미분했을때 깔끔하게 떨어지기 때문에 임의로 앞에 붙여준 것이다.

2

3

  • 그렇다면 J(세타0, 세타1)의 최저점은 어떻게 찾을것인가?

= 오차값을 어떻게 최소화할 것인가?

= cost function 등고선의 골짜기 찾기

  • 임의의 지점에서 시작하여 기울기가 낮아지는 지점쪽으로 계속 이동하는 방법을 쓰는데 그 방법을 Gradient Descent 라고 한다.

기울기 = 비용함수의 미분값

4

  • Gradient descent

5

[실습프리뷰]

위의 회귀분석 예시를 각각의 방법으로 구현해본다.

1) 파이썬 프로그래밍으로 구현

2) numpy를 이용해서 구현

3) scikit-learn을 이용해서 구현

4) spark를 이용해서 구현

1) 파이썬 프로그래밍으로 구현

참고로 변수명 뒤에 _ (언더스코어)가 붙으면 고정된 값임

step1)

x_ = [30, 50, 10]
# 평수

y_ = [34000, 56000, 14000] 
# 단위 : 만원

theta0_ = 5000
theta1_ = 1000

def h(x):
    return theta1_ * x + theta0_
# h(x) = 1000x + 5000 구현

# 평수 30을 넣었을때 실제값과 약간의 차이가 있는 것을 보임
h(30)
35000

step 2)

이제 하고 싶은 것은 gradient decent 방식을 구현해서 조금 더 나은 오차함수를 출력하고 싶음

def cost_function():
    accumulator = 0
    m = len(x_)
    
    for i in range(len(x_)):
        accumulator += (h(x_[i]) - y_[i]) ** 2
    
    return 1/(2*m) * accumulator

def calculate_grad():
    m = len(x_)
        
    grad_theta0 = 1/m * (h(x_[0])-y_[0] + h(x_[1])-y_[1] + h(x_[2])-y_[2])
    grad_theta1 = 1/m * (((h(x_[0])-y_[0]) * x_[0]) + ((h(x_[1])-y_[1]) * x_[1]) + \
                         ((h(x_[2])-y_[2]) * x_[2]))
    
    return grad_theta0, grad_theta1

def print_current_cost():
    print(cost_function())

alpha = 0.001

for i in range(10000):
    grad_theta0, grad_theta1 = calculate_grad()
    theta0_ = theta0_ - alpha * grad_theta0
    theta1_ = theta1_ - alpha * grad_theta1

print_current_cost()
115094.46476318393

2) numpy를 이용해서 구현

import numpy as np

x_np_ = np.array([30, 50, 10])
y_np_ = np.array([34000, 56000, 14000])

m = x_np_.shape[0] # m = 3
alpha = 0.001

x_np_combined_ = np.concatenate([np.ones(m).reshape(m, 1), x_np_.reshape(m,1)], axis=1)
# x_np_combined_ =
# [[ 1. 30.]
#  [ 1. 50.]
# [ 1 .10.]]

theta_ = np.array([5000, 1000]) # theta_ = [5000 1000]

def h_np(x_np_combined_): 
    return x_np_combined_.dot(theta_)

def cost_function_np():
    return 1/(2*m) * np.sum( ( h_np(x_np_combined_) - y_np_ ) ** 2 )

def print_current_cost_np():
    print(cost_function_np())
    
def calculate_grad_np():
    grad_theta = 1/m * x_np_combined_.T.dot(h_np(x_np_combined_) - y_np_)    
    return grad_theta
for i in range(10000):
    grad_theta = calculate_grad_np()
    theta_ = theta_ - alpha * grad_theta
    
print_current_cost_np()
115094.46476318393
theta_
array([3353.35983726, 1045.19837837])

3) scikit-learn으로 구현

from sklearn.linear_model import LinearRegression

m = x_np_.shape[0]
x_np_sk_ = np.array([30, 50, 10]).reshape(m,1)
y_np_sk_ = np.array([34000, 56000, 14000]).reshape(m,1)

lr_sklearn = LinearRegression()

model = lr_sklearn.fit(x_np_sk_, y_np_sk_)
model.coef_
array([[1050.]])
model.intercept_
array([3166.66666667])
model.predict([[30]])
array([[34666.66666667]])

4) spark로 구현

import numpy as np
import pandas as pd

x_np_ = np.array([30, 50, 10])

m = x_np_.shape[0]

x_np_sk_ = np.array([30, 50, 10]).reshape(m,1)
y_np_sk_ = np.array([34000, 56000, 14000]).reshape(m,1)

data = np.concatenate([x_np_sk_, y_np_sk_], axis=1)

pd_df = pd.DataFrame(data,columns=['feature1','label'])

pd_df
feature1 label
0 30 34000
1 50 56000
2 10 14000
import findspark
findspark.init("/home/minman/다운로드/spark-2.4.0-bin-hadoop2.7")

import pyspark
from pyspark.sql import SparkSession

spark = SparkSession.builder.getOrCreate()

df = spark.createDataFrame(pd_df)
df.show()
+--------+-----+
|feature1|label|
+--------+-----+
|      30|34000|
|      50|56000|
|      10|14000|
+--------+-----+
from pyspark.ml.regression import LinearRegression

from pyspark.ml.feature import VectorAssembler

assembler = VectorAssembler(
    inputCols=["feature1"],
    outputCol="features")

df_feature = assembler.transform(df)

spark_lr = LinearRegression(maxIter=10)
spark_lr_model = spark_lr.fit(df_feature)

# Print the coefficients and intercept for linear regression
print("Coefficients: %s" % str(spark_lr_model.coefficients))
print("Intercept: %s" % str(spark_lr_model.intercept))
Coefficients: [1050.000000000002]
Intercept: 3166.6666666666024