回归模型评估指标
均方误差
均方误差(mean_squared_error):是反映估计量与被估计量之间差异程度的一种度量
一般希望估计的均方误差,越小越好
机器学习库sklearn中,我们使用metrics方法实现:
import numpy as np from sklearn.metrics import accuracy_score y_pred = [0, 2, 1, 3] y_true = [0, 1, 2, 3] accuracy_score(y_true, y_pred)
MAE(平均绝对误差)
绝对误差的平均值,能反映预测值误差的实际情况。取值越小,模型准确度度越高。
from sklearn.metrics import mean_absolute_error mean_absolute_error(y_test,y_pred)
MAPE(平均绝对百分比误差)
是 MAE 的变形,它是一个百分比值。取值越小,模型准确度越高。
MAPE = np.mean(np.abs((y_test - y_pred)/y_test))
RMSE(均方根误差)
from sklearn.metrics import mean_squared_error from math import sqrt sqrt(mean_squared_error(y_test,y_pred)) R Square(R方)
将预测值跟只使用均值的情况下相比。取值范围一般【0,1】,结果越靠近 1 模型准确度度越高,结果越靠近 0 直接瞎猜准确度更高,结果为 负数 直接平均值乘以2倍准确度更高。
from sklearn.metrics import r2_score r2_score(y_test,y_pred)
交叉验证
为什么要使用交叉验证?
将原始数据分成K个子集(一般是均分),将每个子集数据分别做一次测试集 (testing test),其余的K-1组子集数据作为训练集(trainning test),这样会得到K个模型,用这K个模型最终的验证集的分类指标的平均数作为此K-CV下分类器的性能指标
当然在分类和回归当中都可以使用交叉验证
#机器学习库sklearn中,我们使用cross_val_score方法实现:
from sklearn.model_selection import cross_val_score scores = cross_val_score(knn, X, y, cv=5) #五折交叉验证 ################定义一个返回cross-validation rmse error函数来评估模型以便可以选择正确的参数######## from sklearn.linear_model import Ridge, RidgeCV, ElasticNet, LassoCV, LassoLarsCV from sklearn.model_selection import cross_val_score def rmse_cv(model): ##使用K折交叉验证模块,将5次的预测准确率打印出 rmse= np.sqrt(-cross_val_score(model, X_train, y_train, scoring="neg_mean_squared_error", cv = 5)) #输入训练集的数据和目标值 return(rmse) model_ridge = Ridge() alphas = [0.05, 0.1, 0.3, 1, 3, 5, 10, 15, 30, 50, 75] cv_ridge = [rmse_cv(Ridge(alpha = alpha)).mean() #对不同的参数alpha,使用岭回归来计算其准确率 for alpha in alphas] cv_ridge #绘制岭回归的准确率和参数alpha的变化图 cv_ridge = pd.Series(cv_ridge, index = alphas) cv_ridge.plot(title = "Validation - Just Do It") plt.xlabel("alpha") plt.ylabel("rmse")
保存模型
机器学习库sklearn中,我们使用joblib方法实现: from sklearn.externals import joblib joblib.dump(knn, 'filename.pkl') knn1 = joblib.load('filename.pkl') #测试读取后的Model print(knn1.score(X_test, y_test))
有人可能会疑惑,为什么要保存模型,一般不是通过一运行就可以了吗,答案是不一定,每次的模型由于数据分割的参数设置的不一样,模型的效果也可能不一样,所以懂得如何保存模型也是不错的。
机器学习中的拟合问题
过拟合是指为了得到一致假设而使假设变得过度严格。避免过拟合是机器学习设计中的一个核心任务。一般是在训练集上评分很高
使用的模型比较复杂,学习能力过强
有噪声存在
数据量有限
过拟合:做的太过好以至于偏离了原本,泛化能力差
欠拟合:泛化能力强,但过于泛化
那么如何解决呢?
寻找参数的最优:超参数优化器
使用sklearn中的学习曲线
具体的解决方案如下:
收集更多的数据
通过正则化引入罚项
选择一个参数相对较少的简单模型
降低数据的维度
L1正则化
过拟合问题产生的原因,直观来说就是某些维度上的权重系数太”偏激”了,正则化通过添加罚项,使得模型的偏差增大,方差减小,使得权重系数均向0趋近,越是”偏激”的权重系数就越是被打压,一定程度上解决了过拟合问题。
如下图所示,当C的值(也就是罚项的倒数)减小时,也就是当罚项增大时,权重系数都在往0逼近
L1和L2的异同点
相同点:都用于避免过拟合
不同点:
(1) L1可以让一部分特征的系数缩小到0,从而间接实现特征选择。所以L1适用于特征之间有关联的情况。
(2) L2让所有特征的系数都缩小,但是不会减为0,它会使优化求解稳定快速。所以L2适用于特征之间没有关联的情况
序列特征选择算法(SBS)
SBS是一个不断删除特征,并通过价值函数进行贪心的特征选择算法,用来降低特征的维度
通过随机森林判断特征的重要性
随机森林可以帮助我们获得特征的重要性等级,从而可以选择出最重要的那几个特征
至于常见的特征筛选,有集成学习里面的各类算法
实现代码
# 使用不同的方法解决过拟合问题 # 1. L1正则 # 2. SBS # 3. RandomForest import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split # 用于分离训练集和验证集 from sklearn.preprocessing import MinMaxScaler # Min-Max归一化 from sklearn.preprocessing import StandardScaler # 标准化 from sklearn.metrics import accuracy_score # 计算分类准确率 from sklearn.svm import SVC # 支持向量机 from sklearn.neighbors import KNeighborsClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from Chapter4.RatingFeature_SBS import SBS df_wine = pd.read_csv('./Data/UCI/wine.data') df_wine.columns = [ 'Class label', # 注意:第一行是ClassLabel, 需要额外添加这个column 'Alcohol', 'Malic acid', 'Ash', 'Alcalinity of ash', 'Magnesium', 'Total phenols', 'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins', 'Color intensity', 'Hue', 'OD280/OD315 of diluted wines', 'Proline ' ] # print('Class labels', np.unique(df_wine['Class label'])) # print(df_wine.head()) X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values # X, y = df_wine.values[:, 1:], df_wine.values[:, 0] 与上面这一句等价 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0) # 对数据进行Min-Max归一化 mms = MinMaxScaler() X_train_norm = mms.fit_transform(X_train) x_test_norm = mms.transform(X_test) # 对数据进行标准化 stdsc = StandardScaler() X_train_std = stdsc.fit_transform(X_train) X_test_std = stdsc.transform(X_test) def solve_by_SBS(num_of_features): knn = KNeighborsClassifier(n_neighbors=2) sbs = SBS(knn, k_features=1) sbs.fit(X_train_std, y_train) # 查看当使用n个特征的时候,哪n个特征最有用,SBS是一个接一个的删掉最不好的特征 n = num_of_features total = df_wine.shape[1]-1 k_n = list(sbs.subsets_[total-n]) return k_n def solve_by_RandomForest(num_of_features): forest = RandomForestClassifier(n_estimators=10000, random_state=0, n_jobs=-1) forest.fit(X_train, y_train) importances = forest.feature_importances_ indices = np.argsort(importances)[::-1] # 返回最优的n个特征的索引 return indices[:num_of_features] def train_by_KNN(X_train_std, y_train, X_test_std, y_test): knn = KNeighborsClassifier(n_neighbors=2, p=2, metric='minkowski') knn.fit(X_train_std, y_train) y_prediction = knn.predict(X_test_std) print('Misclassified samples: %d' % (y_test != y_prediction).sum()) print('Accuracy: %f' % accuracy_score(y_test, y_prediction)) return accuracy_score(y_test, y_prediction) def train_by_SVM(X_train_std, y_train, X_test_std, y_test): svm = SVC(kernel='linear', C=1.0, random_state=0) svm.fit(X_train_std, y_train) y_prediction = svm.predict(X_test_std) print('Misclassified samples: %d' % (y_test != y_prediction).sum()) print('Accuracy: %f' % accuracy_score(y_test, y_prediction)) # 使用SBS方法从1开始查找最优的特征 accuracies = [] for n in range(1, X_train.shape[1]): print('Feature Number', n ,': ') index = solve_by_SBS(num_of_features=n) best_train_std = X_train_std[:, index] best_test_std = X_test_std[:, index] accuracy = train_by_KNN(best_train_std, y_train, best_test_std, y_test) accuracies.append(accuracy) plt.plot(range(len(accuracies)), accuracies, label='SBS', marker='o', color='blue') # 使用RF方法从1开始查找最优的特征 accuracies = [] for n in range(1, X_train.shape[1]): print('Feature Number', n, ': ') index = solve_by_RandomForest(num_of_features=n) best_train_std = X_train_std[:, index] best_test_std = X_test_std[:, index] accuracy = train_by_KNN(best_train_std, y_train, best_test_std, y_test) accuracies.append(accuracy) plt.plot(range(len(accuracies)), accuracies, label='RandomForest', marker='x', color='red') plt.xlabel('Number of Best-Choosed Features') plt.ylabel('Accuracy') plt.xlim([-1, len(accuracies)+1]) plt.ylim([0, 1.2]) plt.legend(loc='upper left') plt.show() # lr = LogisticRegression(penalty='l1', C=0.1) # 感觉惩罚系数没必要这么大,C是惩罚系数的倒数 # lr.fit(X_train_std, y_train) # print('Training accuracy:', lr.score(X_train_std, y_train)) # print('Test accuracy:', lr.score(X_test_std, y_test))