线性回归的推导与简单的一元线性回归代码实现

直入正题,一元线性回归就是一次函数,即 $y=kx+b$

在线性函数中,$x$就是自变量,即模型需要输入的数据,$y$就是因变量,即我们需要预测的值

我们如何拟合一条符合数据变化趋势的曲线呢?这就要涉及误差值了,因为拟合出来的曲线能否代表数据特征,我们需要一个评判标准

曲线绝对无法完全拟合到每一个数据点上,但是我们能在这种拟合中寻找最优的那条曲线,评判依据就是误差值,什么是这里的误差值呢?

公式推导

在这里我们将误差设为$e$,$e=y-kx-b$鉴于误差存在正负的波动所以我们以$|e|$来代表误差的大小,要求最小的误差,即求$|e|$的最小值

在整个训练数据集中就求:$\sum_{n=i}^{n}|e|$的最小值,将公式进行推导,如下:
$$
{min}(\sum_{n=i}^n|e|)\Rightarrow{min}(\sum_{n=i}^n e^2)\Rightarrow{min}(\sum_{n=i}^n ({y_{i}-kx_i-b})^2)
$$
令S为:
$$
S =\sum_{n=i}^n ({y_{i}-kx_i-b})^2
$$
为求S的极值,需要对k,b求偏导,并使其等于0,最后求出k,b的值用于代码的编写:
$$
\begin{cases}
\frac{\partial S}{\partial k} = 2 \times \sum_{i=1}^n (y_i-kx_i-b)(-x_i)
\\\
\frac{\partial S}{\partial b} = 2 \times \sum_{i=1}^n (y_i-kx_i-b)(-1)
\end{cases}
$$

$$
\Rightarrow
\begin{cases}
b = \frac{\sum_{i=1}^n (y_i-kx_i)}{n} = \frac{\sum_{i=1}^n y_i-k \sum_{i=1}^{n} x_i}{n}
\\\
k = \frac{n\times\sum_{i=1}^n x_iy_i-\sum_{i=1}^n y_i\times\sum_{i=1}^n x_i}{n\times\sum_{i=1}^n x^2 - (\sum_{i=1}^n x_i)^2}
\end{cases}
$$

以下是代码部分,采用python语言编写:

生成测试数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
import matplotlib.pyplot as plt

x = np.random.uniform(-10,10,size=100)
y = .4 * x + 3 + np.random.uniform(-1,1,size=100)

f = open('dataset/simulation_data_1d.txt','w')
for i in range(0,100):
line = str(x[i]) + ',' + str(y[i])
f.write(line)
f.write('\n')

plt.plot(x,y,'b.')
plt.show()

编写算法部分

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
import matplotlib.pyplot as plt
import random

data = open('dataset/simulation_data_1d.txt', 'r').read()
# print(data.split('\n'))

# 数据读取
x = []
y = []
for item in data.split('\n'):
if item != '':
item = item.split(',')
x.append(float(item[0]))
y.append(float(item[1]))


# 数据集构建
def seperateData(x, y, test_scale):
# 将x,y进行矩阵组合
data = []
for _x in x:
i = x.index(_x)
data.append([])
if type(_x) == 'list':
for feature in range(len(_x)):
data[i].append(feature)
data[i].append(y[i])
else:
data[i].append(_x)
data[i].append(y[i])

# 切割数据集
train = []
test = []
random.seed(3)
for i in range(len(data)):
count = random.random()
if count > test_scale:
train.append(data[i])
elif count < test_scale:
test.append(data[i])
return train, test


train, test = seperateData(x, y, 0.2)

# 处理成能够用于模型训练的数据结构
X_train = []
Y_train = []
X_test = []
Y_test = []
for item in train:
X_train.append(item[:-1])
Y_train.append(item[-1])
for item in test:
X_test.append(item[:-1])
Y_test.append(item[-1])

Xsum = 0.0
Ysum = 0.0
XY = 0.0
X2sum = 0.0
n = len(Y_train)
# 推导的算法结果部分的实现
for i in range(n):
Xsum += X_train[i][0]
Ysum += Y_train[i]
XY += X_train[i][0] * Y_train[i]
X2sum += X_train[i][0] ** 2
k = (n * XY - Xsum * Ysum) / (n * X2sum - Xsum ** 2)
b = (Ysum - k * Xsum) / n
print("拟合的曲线:y =",k,"* x +",b)

plt.plot(X_train, Y_train, 'b.')
plt.plot(X_test, Y_test, 'r*')
plt.xlabel("Trian_Area")
plt.ylabel("Trian_Price")

# 绘制拟合的曲线
Y = []
for item in X_test:
Y.append(k * item[0] + b)
plt.plot(X_test, Y, 'g-')

plt.show()

总结:我jio的还口以,如有错误欢迎指正