《Machine Learning in Action》—— 剖析支持向量机,优化SMO

薄雾浓云愁永昼,瑞脑销金兽。

愁的很,上次不是更新了一篇关于支持向量机的文章嘛,《Machine Learning in Action》—— 剖析支持向量机,单手狂撕线性SVM。虽然效果还算不错,数据集基本都能够分类正确,模型训练效率的话也还说的过去,但这是基于我们训练样本数据集比较少、迭代次数比较少的前提下。

假如说我们数据集比较大,而且还需要迭代不少次数的话,上一篇文章中使用到的SMO算法的效率可就不敢恭维了,训练的速度可堪比龟龟。月黑风高夜,杀人放火天。不对不对,月黑风高夜,疯狂肝文时。既然一般的SMO算法的效率低下,那怎么说也得进一步优化才行呐。

就在前几天还听见收音机上说,国内外有许多如雷贯耳的大佬都在不断研究新算法来进一步提高SMO算法的训练效率。闻此一言,Taoye心中大喜:"如果我能蹦跶出一个新的优化算法,哥哥我声名远扬的大好机会就来了啊,雄霸天下的抱负就指日可待了啊!哈哈哈哈!!!"想法虽好,可是该怎么优化呢?在这薄雾浓云、月黑风高之夜,Taoye的思绪漫天飞,愁的很。

有心栽花花不开,无心插柳柳成荫。

明明已经知道SMO算法待优化的地方太多了,可是就是不知如何下手,想了老半天,脑阔疼的厉害。此刻实验室空无一人,Taoye转着座椅,双目望向窗外,皎洁的月光总是给人无限遐想。

罢了罢了,与其木讷在这有心栽花花不开,倒不如出去转悠转悠,说不定能捕获个意想不到的收获,给我来了无心插柳柳成荫呢?说走咱就走哇(调调有点不对劲~~),关上空调,披件外套,锁上室门,双手插袋朝外走去。

或许是空调吹太久了,亦或实验室呆太久了,出来的瞬间一股神清气爽的感觉涌上心头,五音不全的我此时还真想高歌一曲。顷之,微凉,好在出门前披了件外套。活动活动筋骨,朝湖边走去。走着走着,不知不觉来到了步行桥,风平浪静的湖面,没有一丝波纹荡起。左转,低头看着湖面中胡子拉碴且憔悴的自己,此时我的眼角又再一次。。。┭┮﹏┭┮ 。。抬头看着湖边零星几对小情侣,或有说有笑、或呢喃窃语、或打情骂俏,滋滋滋,有点儿意思,只有我只身一人还在想着如何优化SMO算法。

等会儿。。。小情侣???优化SMO???

我记得在前面那篇文章中写到的SMO算法的核心思想里,正是不断迭代成双成对的\(\alpha_i\)和\(\alpha_j\),只不过那个时候的这对“小情侣”是随意配对,所以导致的排列组合的可能性太多,从而拉低了整个模型训练的效率。假如说,我那个时候选取这对“小情侣”的时候并不是无意的,而是有意识、有条件的去选取,不就可以避开大量没必要的可能性计算么,这样一来不就可以大大提高模型的训练效率了么???

握了一棵草,乖乖,我真是个天才,这都被我想到了???心头灵光一闪,犹如饥渴春笋听到的第一声惊雷,屁颠屁颠的朝实验室跑去,而一对对小情侣异样且诧异的眼神朝我看来。。。

上述内容部分虚构,仅做引出下文之用。

在这之前,我们先静下心来分析一下上篇文章中SMO的核心算法:

上图是我们在讲解手撕线性SVM中所写到的linear_smo方法,详细请看:《Machine Learning in Action》—— 剖析支持向量机,单手狂撕线性SVM。其中Taoye圈出了三个代码块来给大家介绍下:

第一个代码块,我们可以发现代码行为for i in range(m):,想必大家都知道这是一个循环语句,在这个方法中它具体表达的意思是根据样本数量一次选取索引\(i\),然后通过这个索引来确定\(\alpha_i\)的选择,所以它最终会把所有的样本都“走一遍”。

第二个代码块,是根据\(i\)的值重新在\(m\)中选取一个不与\(i\)相同的\(j\),然后根据这个\(j\)来修改对应的\(\alpha_j\)

第三个就是我们大量的矩阵、向量进行计算的代码块了,我们可以发现,无论前两个\(i、j\)的选取是怎样的,第三个代码块都会去执行、计算,然而有些计算完全是没必要的,这样就大大拉跨了整个SMO算法的效率,这可不是我们想要的。

综上,我们需要在\(\alpha\)的选取上做点文章,使其在一定的跳过第三个代码块的计算。

  • 第一个\(\alpha_i\)的选取

在上一篇文章中,我们也有提到,大多数样本对于决策面的确定都是无用的,只有少数部分的样本点才能确定具体的决策面。而\(\alpha\)与样本之间满足如下关系:

\[ \left\{
\begin{array}{c}
\alpha_i=0 \quad <=> \quad y_i(w^T+b)\geq1\\
\alpha_i=C \quad <=> \quad y_i(w^T+b)\leq1\\
0\leq\alpha_i\leq C \quad <=> \quad y_i(w^T+b)=1\\
\end{array}
\right.
\]

对于第一个\(\alpha_i\)的选取,初始化的\(\alpha\)向量为0,所以第一次迭代是对所有的样本点进行。待第一次迭代完成之后,此时的\(\alpha\)向量已经更新完成了,在之后的迭代过程中,我们就不需要对所有的样本进行遍历了,而是选取在\((0, C)\)区间的\(\alpha_i\)值即可,因为其他的\(\alpha\)值对于最终决策面的确定没有什么影响。

对于第一个\(\alpha_i\)的选取,核心代码思想如下所示,也就是我们的外层循环。其中data_struct是一个数据结构,其内部保存了一些公有地的属性,这个我们后面会讲:

"""
Author:Taoye
微信公众号:玩世不恭的Coder
Explain:外层循环,选取第一个合适alpha
Parameters:
x_data: 样本属性特征矩阵
y_label: 属性特征对应的标签
C:惩罚参数
toler:容错率
max_iter:迭代次数
Return:
b: 决策面的参数b
alphas:获取决策面参数w所需要的alphas
"""
def outer_smo(self, data_struct, x_data, y_label, C, toler, max_iter):
iter_num, ergodic_flag, alpha_optimization_num = 0, True, 0
while (iter_num < max_iter) and ((alpha_optimization_num > 0) or (ergodic_flag)):
alpha_optimization_num = 0
if ergodic_flag:
for i in range(data_struct.m):
alpha_optimization_num += self.inner_smo(i, data_struct)
print("遍历所有样本数据:第%d次迭代,样本为:%d,alpha优化的次数:%d" % (iter_num, i, alpha_optimization_num))
iter_num += 1
else:
no_zero_index = np.nonzero((data_struct.alphas.A > 0) * (data_struct.alphas.A < C))[0]
for i in no_zero_index:
alpha_optimization_num += self.inner_smo(i, data_struct)
print("非边界遍历样本数据:第%d次迭代,样本为:%d,alpha优化的次数:%d" % (iter_num, i, alpha_optimization_num))
iter_num += 1
if ergodic_flag: ergodic_flag = False
elif alpha_optimization_num == 0: ergodic_flag = True
print("迭代次数:%d" % iter_num)
return data_struct.b, data_struct.alphas
  • 第二个\(\alpha_j\)的选取

对于第二个\(\alpha_j\),我们不妨先分析一下前篇文章中SMO算法最终优化之后的\(\alpha_2^{new}\):

\[\alpha_2^{new}=\frac{y_2(E_1-E_2)}{\eta}+\alpha_2^{old}
\]

我们可以发现\(\alpha_2\)主要是靠更新迭代来进行优化,而\(\alpha_2^{old}\)是已知的,我们没有选择的权利,但是\(\frac{y_2(E_1-E_2)}{\eta}\)这一部分的值我们是可控的,也就是说我们要选择合适的\(\alpha_j\)来使得后一部分的值尽可能的大,从而达到快速修改\(\alpha\)向量的目的,才能更快速的实现训练饱和。

简单来说就是\(\alpha_2^{new}\)的变化依赖于\(|E_1-E_2|\),当该绝对值越大,\(\alpha_2\)的变化也就越大。也就是说,\(E_1\)为正的时候,我们的要选择尽可能小的\(E_2\),\(E_1\)为负的时候,我们要选择尽可能大的\(E_2\)。根据这个思想我们就能让这对“小情侣”完美的配对了,美滋滋~~

对于第一个\(\alpha_i\)的选取,核心代码思想如下所示,也就是我们的内层循环的所需要选取\(\alpha_j\)内容:

def select_appropriate_j(self, i, data_struct, E_i):
max_k, max_delta_E, E_j = -1, 0, 0
data_struct.E_cache[i] = [1, E_i]
valid_E_cache_list = np.nonzero(data_struct.E_cache[:, 0].A)[0]
if (len(valid_E_cache_list) > 1):
for k in valid_E_cache_list:
if k == i: continue
E_k = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, k)
delta_E = abs(E_i - E_k)
if (delta_E > max_delta_E): max_k, max_delta_E, E_j = k, delta_E, E_k
return max_k, E_j
else:
j = self.random_select_alpha_j(i, data_struct.m)
E_j = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, j)
return j, E_j

为了方便我们使用有关数据集和模型的一些公共资源,以及方便对它们进行操作,我们需要单独封装一个数据结构(当然了,不封装也没什么问题),该数据结构有关属性解释如下:

  1. x_data:etablish_data随机生成数据集中的属性矩阵
  2. y_label:etablish_data随机生成数据集中的标签
  3. C:惩罚参数
  4. toler:容错率
  5. m:数据样本数
  6. alphas:SMO算法所需要训练的\(\alpha\)向量
  7. b:SMO算法所需要训练的\(b\)参数
  8. E_cache:用于保存误差,第一列为有效标志位,第二列为样本索引对应的误差E

此外,为了提高代码的扩展性和灵活性,还单独抽离了一个方法update_E_k,主要用于更新data_struct对象中的E_cache属性:

def update_E_k(self, data_struct, k):
E_k = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, k) #计算Ek
data_struct.E_cache[k] = [1,E_k]

完整代码:

import numpy as np
import pylab as pl
from matplotlib import pyplot as plt class DataStruct:
def __init__(self, x_data, y_label, C, toler):
self.x_data = x_data
self.y_label = y_label
self.C = C
self.toler = toler
self.m = x_data.shape[0]
self.alphas = np.mat(np.zeros((self.m, 1)))
self.b = 0
self.E_cache = np.mat(np.zeros((self.m, 2))) class OptimizeLinearSVM:
def __init__(self):
pass """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain: 用于生成训练数据集
Parameters:
data_number: 样本数据数目
Return:
x_data: 数据样本的属性矩阵
y_label: 样本属性所对应的标签
"""
def etablish_data(self, data_number):
np.random.seed(38)
x_data = np.concatenate((np.add(np.random.randn(data_number, 2), [3, 3]),
np.subtract(np.random.randn(data_number, 2), [3, 3])),
axis = 0) # random随机生成数据,+ -3达到不同类别数据分隔的目的
temp_data = np.zeros([data_number])
temp_data.fill(-1)
y_label = np.concatenate((temp_data, np.ones([data_number])), axis = 0)
return x_data, y_label """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain: 随机选取alpha_j
Parameters:
alpha_i_index: 第一个alpha的索引
alpha_number: alpha总数目
Return:
alpha_j_index: 第二个alpha的索引
"""
def random_select_alpha_j(self, alpha_i_index, alpha_number):
alpha_j_index = alpha_i_index
while alpha_j_index == alpha_i_index:
alpha_j_index = np.random.randint(0, alpha_number)
return alpha_j_index """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain: 使得alpha_j在[L, R]区间之内
Parameters:
alpha_j: 原始alpha_j
L: 左边界值
R: 右边界值
Return:
L,R,alpha_j: 修改之后的alpha_j
"""
def modify_alpha(self, alpha_j, L, R):
if alpha_j < L: return L
if alpha_j > R: return R
return alpha_j """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain: 计算误差并返回
"""
def calc_E(self, alphas, y_label, x_data, b, i):
f_x_i = float(np.dot(np.multiply(alphas, y_label).T, x_data * x_data[i, :].T)) + b
return f_x_i - float(y_label[i]) """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain: 计算eta并返回
"""
def calc_eta(self, x_data, i, j):
eta = 2.0 * x_data[i, :] * x_data[j, :].T \
- x_data[i, :] * x_data[i, :].T \
- x_data[j, :] * x_data[j,:].T
return eta """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain: 计算b1, b2并返回
"""
def calc_b(self, b, x_data, y_label, alphas, alpha_i_old, alpha_j_old, E_i, E_j, i, j):
b1 = b - E_i \
- y_label[i] * (alphas[i] - alpha_i_old) * x_data[i, :] * x_data[i, :].T \
- y_label[j] * (alphas[j] - alpha_j_old) * x_data[i, :] * x_data[j, :].T
b2 = b - E_j \
- y_label[i] * (alphas[i] - alpha_i_old) * x_data[i, :] * x_data[j, :].T \
- y_label[j] * (alphas[j] - alpha_j_old) * x_data[j, :] * x_data[j, :].T
return b1, b2 def select_appropriate_j(self, i, data_struct, E_i):
max_k, max_delta_E, E_j = -1, 0, 0
data_struct.E_cache[i] = [1, E_i]
valid_E_cache_list = np.nonzero(data_struct.E_cache[:, 0].A)[0]
if (len(valid_E_cache_list) > 1):
for k in valid_E_cache_list:
if k == i: continue
E_k = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, k)
delta_E = abs(E_i - E_k)
if (delta_E > max_delta_E): max_k, max_delta_E, E_j = k, delta_E, E_k
return max_k, E_j
else:
j = self.random_select_alpha_j(i, data_struct.m)
E_j = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, j)
return j, E_j def update_E_k(self, data_struct, k):
E_k = self.calc_E(data_struct.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, k) #计算Ek
data_struct.E_cache[k] = [1,E_k] """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain: smo内层
"""
def inner_smo(self, i, data_strcut):
E_i = self.calc_E(data_strcut.alphas, data_struct.y_label, data_struct.x_data, data_struct.b, i) # 调用calc_E方法计算样本i的误差
if ((data_struct.y_label[i] * E_i < -data_struct.toler) and (data_struct.alphas[i] < data_struct.C)) or ((data_struct.y_label[i] * E_i > data_struct.toler) and (data_struct.alphas[i] > 0)):
j, E_j = self.select_appropriate_j(i, data_strcut, E_i) # 选取一个恰当的j
alpha_i_old, alpha_j_old = data_struct.alphas[i].copy(), data_struct.alphas[j].copy()
if (data_struct.y_label[i] != data_struct.y_label[j]): # 确保alphas在[L, R]区间内
L, R = max(0, data_struct.alphas[j] - data_struct.alphas[i]), min(data_struct.C, data_struct.C + data_struct.alphas[j] - data_struct.alphas[i])
else:
L, R = max(0, data_struct.alphas[j] + data_struct.alphas[i] - data_struct.C), min(data_struct.C, data_struct.alphas[j] + data_struct.alphas[i])
if L == R: print("L==R"); return 0 # L==R时选取下一个样本
eta = self.calc_eta(data_struct.x_data, i, j) # 计算eta值
if eta >= 0: print("eta>=0"); return 0
data_struct.alphas[j] -= data_struct.y_label[j] * (E_i - E_j) / eta
data_struct.alphas[j] = self.modify_alpha(data_struct.alphas[j], L, R) # 修改alpha[j]
self.update_E_k(data_strcut, j)
if (abs(data_strcut.alphas[j] - alpha_j_old) < 0.000001): print("alpha_j修改太小了"); return 0
data_struct.alphas[i] += data_strcut.y_label[j] * data_strcut.y_label[i] * (alpha_j_old - data_strcut.alphas[j])
self.update_E_k(data_strcut, i)
b1, b2= self.calc_b(data_struct.b, data_struct.x_data, data_struct.y_label, data_struct.alphas, alpha_i_old, alpha_j_old, E_i, E_j, i, j) # 计算b值
if (0 < data_struct.alphas[i]) and (data_struct.C > data_struct.alphas[i]): data_struct.b = b1
elif (0 < data_struct.alphas[j]) and (data_struct.C > data_struct.alphas[j]): data_struct.b = b2
else: data_struct.b = (b1 + b2)/2.0
return 1
else: return 0 """
Author:Taoye
微信公众号:玩世不恭的Coder
Explain:外层循环,选取第一个合适alpha
Parameters:
x_data: 样本属性特征矩阵
y_label: 属性特征对应的标签
C:惩罚参数
toler:容错率
max_iter:迭代次数
Return:
b: 决策面的参数b
alphas:获取决策面参数w所需要的alphas
"""
def outer_smo(self, data_struct, x_data, y_label, C, toler, max_iter):
iter_num, ergodic_flag, alpha_optimization_num = 0, True, 0
while (iter_num < max_iter) and ((alpha_optimization_num > 0) or (ergodic_flag)):
alpha_optimization_num = 0
if ergodic_flag:
for i in range(data_struct.m):
alpha_optimization_num += self.inner_smo(i, data_struct)
print("遍历所有样本数据:第%d次迭代,样本为:%d,alpha优化的次数:%d" % (iter_num, i, alpha_optimization_num))
iter_num += 1
else:
no_zero_index = np.nonzero((data_struct.alphas.A > 0) * (data_struct.alphas.A < C))[0]
for i in no_zero_index:
alpha_optimization_num += self.inner_smo(i, data_struct)
print("非边界遍历样本数据:第%d次迭代,样本为:%d,alpha优化的次数:%d" % (iter_num, i, alpha_optimization_num))
iter_num += 1
if ergodic_flag: ergodic_flag = False
elif alpha_optimization_num == 0: ergodic_flag = True
print("迭代次数:%d" % iter_num)
return data_struct.b, data_struct.alphas """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain: 根据公式计算出w权值向量
Parameters:
x_data: 样本属性特征矩阵
y_label: 属性特征对应的标签
alphas:linear_smo方法所返回的alphas向量
Return:
w: 决策面的参数w
"""
def calc_w(self, x_data, y_label, alphas):
x_data, y_label, alphas = np.array(x_data), np.array(y_label), np.array(alphas)
return np.dot((np.tile(y_label.reshape(1, -1).T, (1, 2)) * x_data).T, alphas).tolist() """
Author: Taoye
微信公众号: 玩世不恭的Coder
Explain: 绘制出分类结果
Parameters:
x_data: 样本属性特征矩阵
y_label: 属性特征对应的标签
w:决策面的w参数
b:决策面的参数b
"""
def plot_result(self, x_data, y_label, w, b):
data_number, _ = x_data.shape; middle = int(data_number / 2)
plt.scatter(x_data[:, 0], x_data[:, 1], c = y_label, cmap = pl.cm.Paired)
x1, x2 = np.max(x_data), np.min(x_data)
w1, w2 = w[0][0], w[1][0]
y1, y2 = (-b - w1 * x1) / w2, (-b - w1 * x2) / w2
plt.plot([float(x1), float(x2)], [float(y1), float(y2)]) # 绘制决策面
for index, alpha in enumerate(alphas):
if alpha > 0:
b_temp = - w1 * x_data[index][0] - w2 * x_data[index][1]
y1_temp, y2_temp = (-b_temp - w1 * x1) / w2, (-b_temp - w1 * x2) / w2
plt.plot([float(x1), float(x2)], [float(y1_temp), float(y2_temp)], "k--") # 绘制支持向量
plt.scatter(x_data[index][0], x_data[index][1], s=150, c='none', alpha=0.7, linewidth=2, edgecolor='red') # 圈出支持向量
plt.show() if __name__ == '__main__':
optimize_linear_svm = OptimizeLinearSVM()
x_data, y_label = optimize_linear_svm.etablish_data(50)
data_struct = DataStruct(np.mat(x_data), np.mat(y_label).T, 0.8, 0.00001)
b, alphas = optimize_linear_svm.outer_smo(data_struct, x_data, y_label, data_struct.C, data_struct.toler, 10)
w = optimize_linear_svm.calc_w(x_data, y_label, alphas)
optimize_linear_svm.plot_result(x_data, y_label, w, b)

优化后的分类结果:

这期的内容没那么多,主要是优化了一下上期内容中的SMO算法,从而在一定程度上提高模型的训练效率,由于是手动实现该线性SVM算法,所以模型可能达不到那些框架内置的性能,有兴趣的读者可自行慢慢优化。

关于线性SVM应该就暂时写到这里了,后期的话应该会更新非线性相关的内容。

我是Taoye,爱专研,爱分享,热衷于各种技术,学习之余喜欢下象棋、听音乐、聊动漫,希望借此一亩三分地记录自己的成长过程以及生活点滴,也希望能结实更多志同道合的圈内朋友,更多内容欢迎来访微信公主号:玩世不恭的Coder

参考资料:

[1] 《机器学习实战》:Peter Harrington 人民邮电出版社

[2] 《统计学习方法》:李航 第二版 清华大学出版社

推荐阅读

《Machine Learning in Action》—— 剖析支持向量机,单手狂撕线性SVM

print( "Hello,NumPy!" )

干啥啥不行,吃饭第一名

Taoye渗透到一家黑平台总部,背后的真相细思极恐

《大话数据库》-SQL语句执行时,底层究竟做了什么小动作?

那些年,我们玩过的Git,真香

基于Ubuntu+Python+Tensorflow+Jupyter notebook搭建深度学习环境

网络爬虫之页面花式解析

手握手带你了解Docker容器技术

一文详解Hexo+Github小白建站

​打开ElasticSearch、kibana、logstash的正确方式

《Machine Learning in Action》—— 剖析支持向量机,优化SMO的更多相关文章

  1. 《Machine Learning in Action》—— 剖析支持向量机,单手狂撕线性SVM

    <Machine Learning in Action>-- 剖析支持向量机,单手狂撕线性SVM 前面在写NumPy文章的结尾处也有提到,本来是打算按照<机器学习实战 / Machi ...

  2. 《Machine Learning in Action》—— 懂的都懂,不懂的也能懂。非线性支持向量机

    说在前面:前几天,公众号不是给大家推送了第二篇关于决策树的文章嘛.阅读过的读者应该会发现,在最后排版已经有点乱套了.真的很抱歉,也不知道咋回事,到了后期Markdown格式文件的内容就解析出现问题了, ...

  3. 《Machine Learning in Action》—— Taoye给你讲讲决策树到底是支什么“鬼”

    <Machine Learning in Action>-- Taoye给你讲讲决策树到底是支什么"鬼" 前面我们已经详细讲解了线性SVM以及SMO的初步优化过程,具体 ...

  4. 《Machine Learning in Action》—— 小朋友,快来玩啊,决策树呦

    <Machine Learning in Action>-- 小朋友,快来玩啊,决策树呦 在上篇文章中,<Machine Learning in Action>-- Taoye ...

  5. 《Machine Learning in Action》—— 白话贝叶斯,“恰瓜群众”应该恰好瓜还是恰坏瓜

    <Machine Learning in Action>-- 白话贝叶斯,"恰瓜群众"应该恰好瓜还是恰坏瓜 概率论,可以说是在机器学习当中扮演了一个非常重要的角色了.T ...

  6. 《Machine Learning in Action》—— 浅谈线性回归的那些事

    <Machine Learning in Action>-- 浅谈线性回归的那些事 手撕机器学习算法系列文章已经肝了不少,自我感觉质量都挺不错的.目前已经更新了支持向量机SVM.决策树.K ...

  7. 《Machine Learning in Action》—— Taoye给你讲讲Logistic回归是咋回事

    在手撕机器学习系列文章的上一篇,我们详细讲解了线性回归的问题,并且最后通过梯度下降算法拟合了一条直线,从而使得这条直线尽可能的切合数据样本集,已到达模型损失值最小的目的. 在本篇文章中,我们主要是手撕 ...

  8. Machine Learning in Action(5) SVM算法

    做机器学习的一定对支持向量机(support vector machine-SVM)颇为熟悉,因为在深度学习出现之前,SVM一直霸占着机器学习老大哥的位子.他的理论很优美,各种变种改进版本也很多,比如 ...

  9. 【机器学习实战】Machine Learning in Action 代码 视频 项目案例

    MachineLearning 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远 Machine Learning in Action (机器学习实战) | ApacheCN(apa ...

随机推荐

  1. 多层级makefile

    多层级makefile 当项目变大之后,需要多层级的makefile来编译,每个makefile的具体功能实现参考单源文件目录makefile.然后再在顶层目录写一个总的makefile来实现编译逻辑 ...

  2. python面试题-python相关

    1. __new__.__init__区别,如何实现单例模式,有什么优点 __new__是一个静态方法,__init__是一个实例方法 __new__返回一个创建的实例,__init__什么都不返回 ...

  3. df du linux空间清理,查看文件大小

    df -h ,这个命令用于查看服务器空间,运行后的效果图如下: [root@localhost /]# df -h Filesystem Size Used Avail Use% Mounted on ...

  4. centos8平台使用lscpu查看cpu信息

    一,lscpu所属的包: [root@yjweb ~]# whereis lscpu lscpu: /usr/bin/lscpu /usr/share/man/man1/lscpu.1.gz [roo ...

  5. ORACL-重做日志详解

    作用:oracle重做日志主要目的是数据恢复及数据修改效率提升 前言:oracle重做日志主相关视图: 1.v$log记录当前数据库重做日志组 2.v$logfie记录当前数据库重做日志组状态.类型等 ...

  6. Aspose.Words实现邮件合并功能和打印

    前言 最近公司要做一个B/S架构的web打印系统,主要是可以上传.下载.邮件合并.打印等等,还有就是角色的分配.用户的创建.日志记录等等,跟一般的web系统一样.可能不一样的就是需求:想把excel的 ...

  7. Android测试工具 UIAutomator介绍

    UI Automator 测试工具定义以及用途 UI Automator 测试框架提供了一组 API,用于构建在用户应用和系统应用上执行交互的界面测试.通过 UI Automator API,您可以执 ...

  8. java 常用快捷键及命令积累

    ctl + shift + o--->导入所需包,删掉没有被引用的包 ctl + / --->添加多行注释 ctl + \--->删除多行注释

  9. 腾讯云服务器简单搭建并部署WEB文件

    废话不多说直接上图 提前准备以下软件 1. Xshell6 链接你的服务器用 2. FileZilla 上传文件使用 首先你得有服务器吧,去某云买一个,我买的额配置如下 然后去控制台---登录  修改 ...

  10. 6个冷门但实用的pandas知识点

    1 简介 pandas作为开展数据分析的利器,蕴含了与数据处理相关的丰富多样的API,使得我们可以灵活方便地对数据进行各种加工,但很多pandas中的实用方法其实大部分人都是不知道的,今天就来给大家介 ...