寻找合适的机器学习模型
有时候为了做演示和例子,需要手动构造一些数据,例如通过以下方式构造特征变量和目标变量:利用随即函数np.random.rand()生成0,1之间的随机数
N = 100
x 1= np.random.rand(N) * 6 - 3 生成-3到3之间的随机数,100个
x 2= np.random.rand(N) * 4 - 2
x1.sort()
x2.sort()
y = np.sin(x1) + np.cos(x2)+np.random.randn(N) * 0.05 加入一些噪声
data = pd.DataFrame({‘f1’:pd.Series(x1),’f2’:pd.Series(x2)},index=range(len(x1)))
label = pd.Series(y,index=range(y))
分类与回归
对于分类问题,一般适合的并且常用的模型有如下:
逻辑回归
sklearn.linear_model.LogisticRegression(penalty=’l2’, tol=0.0001,
C=1.0,
random_state=None,
solver=’liblinear’,
max_iter=100,
multi_class=’ovr’,
)
原理就是令几率的自然对数设为线性模型,然后就能获得模型给出的概率是一个sigmoid函数。
Penalty参数选择控制模型结构风险的正则项(范数类型),一般就用L2.
C为控制正则项影响程度的系数,取值越小那么正则项的作用就会越大。
Solver 是优化求解方法
multi_class 选择‘ovr’表示训练二分类模型, ‘multinomial’表示多分类
还有能够自己寻找最优参数C的模型,sklearn.linear_model.LogisticRegressionCV,更多细节看手册
支持向量机
1.用于分类问题
sklearn.svm.SVC(C=1.0,
kernel=’rbf’,
degree=3,
gamma=’auto’,
tol=0.001,
class_weight=None,
decision_function_shape=None,
random_state=None)
原理就是在特征维度空间找到区分不同样本的最大间隔平面,使得离两端的支持向量距离最大。
C参数为损失函数的系数,参数C的取值决定了alpha(每个训练样本对超平面参数的贡献参数)的最大取值,范围是[0,C]
Kernel为选择的核函数
Degree为多项式的系数,当核函数选择为poly时有效
Gamma为核函数中的系数,当核函数接近零时候,则模型退化为线性SVM,默认取值为特征个数的倒数(取值越大,超平面越精确,但是容易引起过拟合)
decision_function_shape为多分类解决方法,‘ovo’, ‘ovr’为两个选择项,前者使用构造两两类别二分类器,后者构造与类别数量相同个数的二分类器来解决多分类的问题
class_weight为类别权重系数
Kernel为核函数,可以选择‘linear’, ‘poly’,‘rbf’, ‘sigmoid’, ‘precomputed’
clf.fit(x_train, y_train.ravel(),sample_weight)
fit函数中可以设置sample_wejght,用以调整样本的权重,格式为一个数组,里面的每个元素代表每个样本的权重。
# 准确率
print(clf.score(x_train, y_train)) # 精度
print('训练集准确率:', accuracy_score(y_train, clf.predict(x_train)))
print(clf.score(x_test, y_test))
print('测试集准确率:', accuracy_score(y_test, clf.predict(x_test)))
进行多分类问题的时候,通过decision_function_shape系数决定所用的二分类器组合方法
例如:
clf = svm.SVC(C=1, kernel='rbf', gamma=1, decision_function_shape='ovr')
进行训练之后,可以输出多分类问题的判断结果:
print(clf.decision_function(x))
输出的内容是:每一行输出n个数值(有正负),n为测试的样本个数
每一个输出代表该样本与某一个svm超平面的距离,选择其中最大的值,则表示该样本属于这个类别
通过svc的训练可以输出一些信息:
print('支撑向量的数目:', clf.n_support_)
print('支撑向量的系数:', clf.dual_coef_)
print('支撑向量:', clf.support_)
解决不平衡数据的问题:
clfs = [svm.SVC(C=1, kernel='linear'),
svm.SVC(C=1, kernel='linear', class_weight={-1: 1, 1: 50}),
svm.SVC(C=0.8, kernel='rbf', gamma=0.5, class_weight={-1: 1, 1: 2}),
svm.SVC(C=0.8, kernel='rbf', gamma=0.5, class_weight={-1: 1, 1: 10})]
通过设置不同的class_weight,来提高不平衡数据的分类效果,一般不用将class_weight设置成样本数量比例的倒数,不用设置那么大。
以下代码段使用svm解决一个二分类问题,其中进行了参数C,核函数以及系数的调参,并将分类结果可视化:
import numpy as np
import pandas as pd
from sklearn import svm
from sklearn.metrics import accuracy_score
import matplotlib as mpl
import matplotlib.colors
import matplotlib.pyplot as plt
if __name__ == "__main__":
data = pd.read_csv('..\\bipartition.txt', sep='\t', header=None)
x, y = data[[0, 1]], data[2]
特征为x,label为y
# 分类器
clf_param = (
('linear', 0.1), ('linear', 0.5), ('linear', 1), ('linear', 2),
('rbf', 1, 0.1), ('rbf', 1, 1), ('rbf', 1, 10), ('rbf', 1, 100),
('rbf', 5, 0.1), ('rbf', 5, 1), ('rbf', 5, 10), ('rbf', 5, 100)
)
x1_min, x2_min = np.min(x, axis=0)
x1_max, x2_max = np.max(x, axis=0)
x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]
grid_test = np.stack((x1.flat, x2.flat), axis=1)
cm_light = mpl.colors.ListedColormap(['#77E0A0', '#FFA0A0'])
cm_dark = mpl.colors.ListedColormap(['g', 'r'])
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
plt.figure(figsize=(13, 9), facecolor='w')
for i, param in enumerate(clf_param):
clf = svm.SVC(C=param[1], kernel=param[0])
if param[0] == 'rbf':
clf.gamma = param[2]
title = '高斯核,C=%.1f,$\gamma$ =%.1f' % (param[1], param[2])
else:
title = '线性核,C=%.1f' % param[1]
clf.fit(x, y)
y_hat = clf.predict(x)
print('准确率:', accuracy_score(y, y_hat))
# 画图
print(title)
print('支撑向量的数目:', clf.n_support_)
print('支撑向量的系数:', clf.dual_coef_)
print('支撑向量:', clf.support_)
plt.subplot(3, 4, i+1)
grid_hat = clf.predict(grid_test) # 预测分类值
grid_hat = grid_hat.reshape(x1.shape) # 使之与输入的形状相同
plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light, alpha=0.8)
plt.scatter(x[0], x[1], c=y, edgecolors='k', s=40, cmap=cm_dark) # 样本的显示
plt.scatter(x.loc[clf.support_, 0], x.loc[clf.support_, 1], edgecolors='k', facecolors='none', s=100, marker='o') # 支撑向量
z = clf.decision_function(grid_test)
# print 'z = \n', z
print('clf.decision_function(x) = ', clf.decision_function(x))
print('clf.predict(x) = ', clf.predict(x))
z = z.reshape(x1.shape)
plt.contour(x1, x2, z, colors=list('kbrbk'), linestyles=['--', '--', '-', '--', '--'],linewidths=[1, 0.5, 1.5, 0.5, 1], levels=[-1, -0.5, 0, 0.5, 1])
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.title(title, fontsize=12)
plt.suptitle('SVM不同参数的分类', fontsize=16)
plt.tight_layout(1.4)
plt.subplots_adjust(top=0.92)
plt.show()
2.Svm 用于回归模型
当svm用来处理回归问题的时候,就是利用超平面作为回归的预测的函数模型
超平面利用个别的样本点建立起来的,并非所有回归样本都参与计算超平面,超平面在回归样本中建立,起到回归模型的作用。
sklearn.svm.SVR(kernel=’rbf’,
degree=3,
gamma=’auto’,
C=1.0)
参数与svc类似。
from sklearn.svm import SVR
svr_rbf = SVR(kernel='rbf', C=1e3, gamma=0.1)
svr_lin = SVR(kernel='linear', C=1e3)
svr_poly = SVR(kernel='poly', C=1e3, degree=2)
y_rbf = svr_rbf.fit(X, y).predict(X)
y_lin = svr_lin.fit(X, y).predict(X)
y_poly = svr_poly.fit(X, y).predict(X)
树结构模型
sklearn.tree.DecisionTreeClassifier(criterion=’gini’,
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
max_features=None,
random_state=None,
max_leaf_nodes=None
)
那个分裂准则可以选“gini” 是基尼指数,那个 “entropy” 是信息熵
Depth不要太大,小心过拟合
树结构模型都是可以返回特征重要程度的 dtc.feature_importances_
sklearn.tree.DecisionTreeRegressor(criterion=’mse’, max_depth=None,
min_samples_split=2, min_samples_leaf=1,
max_features=None,
random_state=None, max_leaf_nodes=None,
)
Criterion参数是用来设定误差评判准则,mse或者mae ,用来寻找最佳分裂点,就是让分裂后的样本的目标变量通过这个误差准则计算后的误差最小,也就是拿分裂后在同一叶结点中的样本的目标变量的平均值与各自真实目标变量的值对比计算误差。
sklearn.tree.ExtraTreeClassifier(criterion=’gini’, splitter=’random’, max_depth=None,
min_samples_split=2, min_samples_leaf=1,
max_features=’auto’,
random_state=None, max_leaf_nodes=None,
)
这是另一种单独的树结构模型,据说在寻找最优分裂特征以及分割点的时候,引入了一定的随机性,但是最是作为融合模型的一个子模型,不要单独使用。
利用决策树做多输出问题,例子如下:
N = 4
x = np.random.rand(N) * 8 - 4 # [-4,4)
x.sort()
x.reshape(-1,1) 将x改成1列的形状
y1 = 16 * np.sin(x) ** 3 + np.random.randn(N)*0.5
y2 = 13 * np.cos(x) - 5 * np.cos(2*x) - 2 * np.cos(3*x) - np.cos(4*x) + np.random.randn(N)*0.5
y = np.vstack((y1, y2)).T 将y1,y2对应位置的元素两两组队,构成双元素目标变量
reg = DecisionTreeRegressor(criterion='mse', max_depth=deep)
dt = reg.fit(x, y)
x_test = np.linspace(x.min(), x.max(), num=1000).reshape(-1, 1) 还是通过采样的方式生成test数据
print(x_test)
y_hat = dt.predict(x_test)
print(y_hat)
K近邻
sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, weights=’uniform’, algorithm=’
auto’, leaf_size=30, p=2)
这个模型原理很简单,就是拿到要预测的新样本时,把它的特征和训练样本进行比较,找到相近的K个样本,通过这些最相近的训练样本的label给出新样本的label。
n_neighbors参数就是需要的近邻个数
weights参数就是给每个近邻的权重,可以选’uniform’或者‘distance’,越近权重越大
algorithm 参数就是寻找近邻的算法,可以调参试试,{‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}
sklearn.neighbors.KNeighborsRegressor(n_neighbors=5, weights=’uniform’, algorithm=’
auto’, leaf_size=30, p=2)
用K近邻来做回顾貌似就不常用了。
线性模型
根据最基本的线性回归,再加上控制模型结构风险的正则项,就得到了常用的回归线性模型,效果还不错。
sklearn.linear_model.Lasso(alpha=1.0, max_iter=1000, tol=0.0001,random_state=None)
这是带有L1范数正则项的线性回归,主要取调节正则项的系数alpha,实践发现,效果一般都还不错。
sklearn.linear_model.LassoCV(eps=0.001, n_alphas=100, alphas=None, max_iter=1000,tol=0.0001 , cv=None,random_state=None)
这是一个能够根据内部交叉验证寻找最优alpha的lasso,
主要可以控制一下alphas。可以设为从0.001到100的一个array。还有cv
ridge = LassoCV(alphas=np.logspace(-3, 2, 20), fit_intercept=False)
sklearn.linear_model.Ridge(alpha=1.0,max_iter=None, tol=0.001, random_state=None)
这就是‘岭回归’,与lasso的不同就是它采用的是L2范数正则项,主要调节的参数也就是alpha。
sklearn.linear_model.RidgeCV(alphas=(0.1, 1.0, 10.0), , scoring=None, cv=None)
这是一个能够根据内部交叉验证寻找最优alpha的ridge,
主要可以控制一下alphas。可以设为从0.001到100的一个array。还有cv
ridge = RidgeCV(alphas=np.logspace(-3, 2, 20), fit_intercept=False)
sklearn.linear_model.ElasticNet(alpha=1.0, l1_ratio=0.5,max_iter=1000,tol=0.0001, random_state=None,)
该模型其实是混合了两种正则项的线性回归
参数可以这一下l1_ratio=0.5,可以调参数试试