14장. 단순 회귀 분석

가설 : 친구 수가 많은 것이 사용자의 사이트 체류 시간을 더 길게 만든다.

${y_i} = \beta{x_i} + \alpha + {\epsilon_i}$


In [1]:
from collections import Counter, defaultdict
from linear_algebra import vector_subtract
from stats import mean, correlation, standard_deviation, de_mean
from gradient_descent import minimize_stochastic
import math, random

In [2]:
#만약 알파와 베타가 이미 구해졌다면...
def predict(alpha, beta, x_i):
    return beta * x_i + alpha

In [3]:
#출력값 y_i가 주어졌으니 알파와 베타에 대한 오류를 계산할 수 있다.
def error(alpha, beta, x_i, y_i):
    """실제 결과가 y_i일때, beta * x_i + alpha로 계산된 예측값의 오류"""
    return y_i - predict(alpha, beta, x_i)

In [4]:
#x_1의 예측값이 너무 높고 x_2으 예측값이 너무 낮다면 오류값이 서로 상쇄되기 때문에...
#오류의 제급값을 더해줌
def sum_of_squared_errors(alpha, beta, x, y):
    return sum(error(alpha, beta, x_i, y_i) ** 2
              for x_i, y_i in zip(x,y))

LSM(Least Square Method) $\Rightarrow$ sum_of_squared_errors를 최소화 해주는 알파, 베타값을 찾는것


In [5]:
def least_squares_fit(x, y):
    """x와 y가 학습 데이터로 주어졌을 때 오류의 제곱값을 최소화해 주는 알파와 베타를 계산"""
    beta = correlation(x, y) * standard_deviation(y) / standard_deviation(x)
    alpha = mean(y) - beta * mean(x)
    return alpha, beta

In [33]:
correlation([1,2], [1,3])


Out[33]:
0.9999999999999999

In [6]:
num_friends_good = [49,41,40,25,21,21,19,19,18,18,16,15,15,15,15,14,14,13,13,13,13,12,12,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
daily_minutes_good = [68.77,51.25,52.08,38.36,44.54,57.13,51.4,41.42,31.22,34.76,54.01,38.79,47.59,49.1,27.66,41.03,36.73,48.65,28.12,46.62,35.57,32.98,35,26.07,23.77,39.73,40.57,31.65,31.21,36.32,20.45,21.93,26.02,27.34,23.49,46.94,30.5,33.8,24.23,21.4,27.94,32.24,40.57,25.07,19.42,22.39,18.42,46.96,23.72,26.41,26.97,36.76,40.32,35.02,29.47,30.2,31,38.11,38.18,36.31,21.03,30.86,36.07,28.66,29.08,37.28,15.28,24.17,22.31,30.17,25.53,19.85,35.37,44.6,17.23,13.47,26.33,35.02,32.09,24.81,19.33,28.77,24.26,31.98,25.73,24.86,16.28,34.51,15.23,39.72,40.8,26.06,35.76,34.76,16.13,44.04,18.03,19.65,32.62,35.59,39.43,14.18,35.24,40.13,41.82,35.45,36.07,43.67,24.61,20.9,21.9,18.79,27.61,27.21,26.61,29.77,20.59,27.53,13.82,33.2,25,33.1,36.65,18.63,14.87,22.2,36.81,25.53,24.62,26.25,18.21,28.08,19.42,29.79,32.8,35.99,28.32,27.79,35.88,29.06,36.28,14.1,36.63,37.49,26.9,18.58,38.48,24.48,18.95,33.55,14.24,29.04,32.51,25.63,22.22,19,32.73,15.16,13.9,27.2,32.01,29.27,33,13.74,20.42,27.32,18.23,35.35,28.48,9.08,24.62,20.12,35.26,19.92,31.02,16.49,12.16,30.7,31.22,34.65,13.13,27.51,33.2,31.57,14.1,33.42,17.44,10.12,24.42,9.82,23.39,30.93,15.03,21.67,31.09,33.29,22.61,26.89,23.48,8.38,27.81,32.35,23.84]

In [14]:
alpha, beta = least_squares_fit(num_friends_good, daily_minutes_good)
print("alpha", alpha)
print("beta", beta)
# 즉, n명의 친구가 있는 사용자는 하루 평균 ( 22.947 + n * 0.903 )분을 사이트에서 보낸다.
# 친구가 없는 사용자는 23분, 한명씩 늘어날수록 1분씩 증가


alpha 22.94755241346903
beta 0.903865945605865

In [12]:
# 모델이 주어진 데이터에 얼마나 적합한지 알아보기 위해..
# 결정계수(R제곱값) 수치를 사용 : 종속 변수의 총 변화량 중 모델이 잡아낼 수 있는 변화량의 비율을 의미

def total_sum_of_squares(y):
    """평균을 기준으로 y_i의 변화량을 제곱한 값의 총합"""
    return sum(v ** 2 for v in de_mean(y))

def r_squared(alpha, beta, x, y):
    """모델이 잡아낼 수 있는 변화량의 비율은
    1 - 모델이 잡아내지 못하는 변화량의 비율로 계산할 수 있다"""
    return 1.0 - (sum_of_squared_errors(alpha, beta, x, y) /
                  total_sum_of_squares(y))

In [13]:
print("r-squared", r_squared(alpha, beta, num_friends_good, daily_minutes_good))


r-squared 0.3291078377836305

경사하강법 사용


In [15]:
#만약 theta = [alpha, beta]로 설정하면 경사하강법을 통해 모델을 만들 수 있다.
def squared_error(x_i, y_i, theta):
    alpha, beta = theta
    return error(alpha, beta, x_i, y_i) ** 2

def squared_error_gradient(x_i, y_i, theta):
    alpha, beta = theta
    return [-2 * error(alpha, beta, x_i, y_i),       # alpha에 대한 편미분
            -2 * error(alpha, beta, x_i, y_i) * x_i] # beta에 대한 편미분

In [18]:
#임의의 알파와 베타 값으로 시작
random.seed(0)
theta = [random.random(), random.random()]
alpha, beta = minimize_stochastic(squared_error,
                                  squared_error_gradient,
                                  num_friends_good,
                                  daily_minutes_good,
                                  theta,
                                  0.0001)
print("gradient descent:")
print("alpha", alpha)
print("beta", beta)


gradient descent:
alpha 22.93746417548679
beta 0.9043371597664965

최대우도추정법


In [ ]: