承接上篇批量梯度下降算法(BGD),文章见:https://blog.csdn.net/CYH00_/article/details/99674407
批量梯度随机下降算法虽然处理数据时考虑更加周全,数据结果更加准确可靠,毕竟BGD每一次数据计算都会遍历一次所有样本数据,所以复杂度是很大的,鉴于此,在数据集更加庞大时,一般很少选择BGD算法,因为效率低,耗时长。此时另一个合适的算法就是随机梯度下降算法(SGD),一次计算只用到一个样本(个人感觉SGD跟多元函数求极值的方法很像),虽然准确度可能达不到BGD那样,但是效率更高,而且因其“随机”,所以陷入局部最小值问题的可能性被大大降低,因此在某些情况下,SGD相比BGD性价比更高。
接下来同样以sklearn里的Boston数据集为例,这次尝试用随机梯度下降算法训练并预测数据。并且将BGD和SGD两种方法求得的结果做一个对比。
一.设计SGD程序如下:
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
51import numpy as np from linear.simpleline import simplelinear as sim #采用随机梯度下降算法解多元线性规划 class sgd: def __init__(self): self.theat_ = None self.theat_list = None self.last_dJ = None def dJ(self,theat,x_b_i,y_i): '''计算梯度(传入数据为单个样本)''' assert len(theat) == len(x_b_i) theat = np.array(theat) x_b_i = np.array(x_b_i) y_i = np.array(y_i) return 2 * (x_b_i.T) * (x_b_i .dot(theat) - y_i) def sgradient(self,x_b,y,i_iters): #i_iters为次数 assert len(x_b) == len(y) assert i_iters >= 1 def Eta(t): t0 = 5 t1 = 50 return t0 / (t + t1) x_b = np.array(x_b) y = np.array(y) x_b = np.hstack([np.ones((len(x_b),1)),x_b]) ini_theat = np.zeros(x_b.shape[1]) theat = ini_theat self.theat_list = [] self.theat_list.append(theat) for i in range(i_iters): index = np.random.permutation(len(x_b)) x_b_new = x_b[index] y_new = y[index] for j in range(len(x_b)): g = self.dJ(theat,x_b_new[j],y_new[j]) theat = theat - Eta(i * len(x_b) + j) * g self.theat_list.append(theat) self.last_dJ = g self.theat_ = theat return self.theat_list def score(self,x_test,y_test): #计算线性相关程度R assert x_test.shape[0] == y_test.shape[0] x_test = np.hstack([np.ones((len(x_test),1)),x_test]) y_predict = x_test .dot(self.theat_) def mse(y_test,y_predict): return np.sum((y_test - y_predict) ** 2) / len(y_predict) def R_R(y_test, y_predict): s = mse(y_test, y_predict) d = np.var(y_test) return 1 - s / d return R_R(y_test,y_predict)
这里解释为什么文章开头时随机二字打上了引号,因为一旦过于随机,比如n次都取到样本1(极端情况可能性很小,但是也有可能)或者取的样本都是前几个。总而言之就是随机取到的样本根本不完全,有很多样本都被随机忽略掉了,所以不具有说服力,因此在设计遍历函数时要考虑这个问题(具体见上述代码中的sgradient函数)。
二.以下是载入数据(Boston)并进行归一化处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16from cyh.train_test_split import t_t_split #这里用的是自己设计的数据分类函数,也可以采用sklearn里面的train_test_split from sklearn.preprocessing import StandardScaler data = datasets.load_boston() t = data.data r = data.target x = t[r < 50] y = r[r < 50] x_train,y_train,x_test,y_test = t_t_split(x,y,0.2,666) #自己做实验时最好设置一个随机种子,以免每次输出结果不一样 m = StandardScaler() m.fit(x_train) x_train = m.transform(x_train) m.fit(x_test) x_test = m.transform(x_test)
三.分别采用BGD和SGD进行预测,并比较结果:
1
2
3
4
5
6
7
8
9
10
11
12
13from linear.bgd import gd from linear.sgd import sgd n = gd() n.gra(x_train,y_train,0.01) #批量梯度下降算法 print(n.theat) m = sgd() m.sgradient(x_train,y_train,500) #随机梯度下降算法 print(m.theat_) print(m.score(x_test,y_test)) #计算线性相关程度R
四.结果对比分析:
1
2
3
4
5
6
7[21.55382653 -1.0510041 0.90432038 -0.28228354 0.17807247 -1.5876832 2.22136885 -0.68691468 -2.61226707 2.38322627 -2.36377392 -1.81554557 0.4816466 -2.57338312] [21.55396184 -1.04997861 0.9021548 -0.28909283 0.17894546 -1.58628975 2.22141016 -0.68766406 -2.61303714 2.36859213 -2.34657215 -1.81477483 0.48119676 -2.57290246] 0.801699511338954
分析知BGD和SGD得到结果几乎是一样的,并且线性相关程度较好。在本例中,测试SGD比BGD耗时长(不过并未打脸之前说的,主要是因为为了追求精度,所以我把遍历次数设为500,比较大了,这跟SGD的本意就有点相违背了),但在数据量异常庞大时,SGD相比BGD在时间消耗上肯定是有非常明显的优势的。
文章内容若有不妥之处,还请诸位大佬批评指正,谢谢了。
最后
以上就是酷酷冬瓜最近收集整理的关于ML——基于梯度下降算法(SGD)下的多元线性回归问题的全部内容,更多相关ML——基于梯度下降算法(SGD)下内容请搜索靠谱客的其他文章。
发表评论 取消回复