-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathlinear_regression.py
More file actions
113 lines (81 loc) · 5 KB
/
linear_regression.py
File metadata and controls
113 lines (81 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"""
Created on Mon Sep 16 02:19:00 2019
@author: Neeraj
Description: Implemention of simple linear regression algorithm from scratch in Python.
Reference: Chapter 14: Simple Linear Regression
"""
def predict(alpha: float, beta: float, x_i: float) -> float:
return beta * x_i + alpha
def error(alpha: float, beta: float, x_i: float, y_i: float) -> float:
"""
The error from predicting beta * x_i + alpha
when the actual value is y_i
"""
return predict(alpha, beta, x_i) - y_i
from vector_operations import Vector;
def sum_of_sqerrors(alpha: float, beta: float, x: Vector, y: Vector) -> float:
return sum(error(alpha, beta, x_i, y_i) ** 2
for x_i, y_i in zip(x, y))
from typing import Tuple
from statistics import correlation, standard_deviation, mean;
def least_squares_fit(x: Vector, y: Vector) -> Tuple[float,float]:
"""Given two vectors x and y,
find the least-squares value of alpha and beta"""
beta = correlation(x,y)*standard_deviation(y)/standard_deviation(x)
alpha = mean(y) - beta*mean(x)
#print(alpha, beta)
return alpha, beta
x = [i for i in range(-100, 110, 10)]
y = [3 * i - 5 for i in x]
least_squares_fit(x,y)
num_friends = [100.0,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 = [1,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]
daily_hours = [dm / 60 for dm in daily_minutes]
outlier = num_friends.index(100) # index of outlier
num_friends_good = [x
for i, x in enumerate(num_friends)
if i != outlier]
daily_minutes_good = [x
for i, x in enumerate(daily_minutes)
if i != outlier]
daily_hours_good = [dm / 60 for dm in daily_minutes_good]
alpha, beta = least_squares_fit(num_friends_good, daily_minutes_good)
print(alpha, beta)
from typing import List
def de_mean(xs: List[float]) -> List[float]:
"""Translate xs by subtracting its mean (so the result has mean 0)"""
x_bar = mean(xs)
return [x - x_bar for x in xs]
def total_sum_of_squares(y: Vector) -> float:
"""the total squared variation of y_i's from their mean"""
return sum(v ** 2 for v in de_mean(y))
def r_squared(alpha: float, beta: float, x: Vector, y: Vector) -> float:
"""The fraction of variation in y captured by the model,
which equals 1-the fraction not captured by the model"""
return 1.0 - (sum_of_sqerrors(alpha, beta, x, y)
/total_sum_of_squares(y))
r_squared(alpha, beta, num_friends_good, daily_minutes_good)
# using gradient descent to solve linear regression problem
import random
import tqdm
from gradient_descent import gradient_step;
num_epochs = 10000
random.seed(0)
guess = [random.random(), random.random()]
learning_rate = 0.00001
with tqdm.trange(num_epochs) as t:
for _ in t:
alpha, beta = guess # initial guess
# partial derivative of loss wrt alpha
grad_a = sum(2 * error(alpha, beta, x_i, y_i)
for x_i, y_i in zip(num_friends_good, daily_minutes_good))
# partial derivative of loss wrt beta
grad_b = sum(2*error(alpha, beta, x_i, y_i)*x_i
for x_i, y_i in zip(num_friends_good, daily_minutes_good))
# computes loss to stick tqdm description
loss = sum_of_sqerrors(alpha, beta,
num_friends_good, daily_minutes_good)
t.set_description(f"loss: {loss:3f}")
# Finally update the guess
guess = gradient_step(guess, [grad_a, grad_b], -learning_rate)
guess