一、分类指标评价
- 混淆矩阵
二分类问题,混淆矩阵2*2
TN:真实值为0,预测值为0,即我们预测是negative,预测正确
FP:真实值为0,预测值为1,即我们预测是positive,预测错误
FN:真实值为1,预测值为0,即我们预测是negative,预测错误
TP:真实值为1,预测值为1,即我们预测是positive,预测正确
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
digits = datasets.load_digits()
X = digits.data
y = digits.target.copy()
# 要构造偏斜数据,将数字9的对应索引的元素设置为1,0~8设置为0
y[digits.target==9]=1
y[digits.target!=9]=0
# 使用逻辑回归做一个分类
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
log_reg = LogisticRegression()
log_reg.fit(X_train,y_train)
# 得到X_test所对应的预测值
y_log_predict = log_reg.predict(X_test)
log_reg.score(X_test, y_test)
TN
def TN(y_true, y_predict):
assert len(y_true) == len(y_predict)
# (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
# 向量与向量按位与,结果还是布尔向量
# np.sum 计算布尔向量中True的个数(True记为1,False记为0)
return np.sum((y_true == 0) & (y_predict == 0)) # 向量与向量按位与,结果还是向量
TN(y_test, y_log_predict)
FP
def FP(y_true, y_predict):
assert len(y_true) == len(y_predict)
# (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
# 向量与向量按位与,结果还是布尔向量
# np.sum 计算布尔向量中True的个数(True记为1,False记为0)
return np.sum((y_true == 0) & (y_predict == 1)) # 向量与向量按位与,结果还是向量
FP(y_test, y_log_predict)
FN
def FN(y_true, y_predict):
assert len(y_true) == len(y_predict)
# (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
# 向量与向量按位与,结果还是布尔向量
# np.sum 计算布尔向量中True的个数(True记为1,False记为0)
return np.sum((y_true == 1) & (y_predict == 0)) # 向量与向量按位与,结果还是向量
FN(y_test, y_log_predict)
TP
def TP(y_true, y_predict):
assert len(y_true) == len(y_predict)
# (y_true == 0):向量与数值按位比较,得到的是一个布尔向量
# 向量与向量按位与,结果还是布尔向量
# np.sum 计算布尔向量中True的个数(True记为1,False记为0)
return np.sum((y_true == 1) & (y_predict == 1)) # 向量与向量按位与,结果还是向量
TP(y_test, y_log_predict)
混淆矩阵
def confusion_matrix(y_true, y_predict):
return np.array([
[TN(y_true, y_predict), FP(y_true, y_predict)],
[FN(y_true, y_predict), TP(y_true, y_predict)]
])
confusion_matrix(y_test, y_log_predict)
输出结果
array([[403, 2],
[ 9, 36]])
2. 精准率
精准率(查准率):预测值为1,且预测对了的比例,即:我们关注的那个事件,预测的有多准。
def precision_score(y_true, y_predict):
tp = TP(y_true, y_predict)
fp = FP(y_true, y_predict)
try:
return tp / (tp + fp)
except:
return 0.0
precision_score(y_test, y_log_predict)
- 召回率
召回率(查全率):所有真实值为1的数据中,预测对了的个数,即:我们关注的那个事件真实的发生情况下,我们成功预测的比例是多少
def recall_score(y_true, y_predict):
tp = TP(y_true, y_predict)
fn = FN(y_true, y_predict)
try:
return tp / (tp + fn)
except:
return 0.0
recall_score(y_test, y_log_predict)
scikit-learn直接调用混淆矩阵,精准率和召回率
#混淆矩阵
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test, y_log_predict)
#精准率
from sklearn.metrics import precision_score
precision_score(y_test, y_log_predict)
#召回率
from sklearn.metrics import recall_score
recall_score(y_test, y_log_predict)
4. F1 Score
其中一个值小,F1 score就很小,必须两个值都大F1 score才大
#F1 Score 是精准率和召回率的调和平均值
import numpy as np
def f1_score(precision, recall):
try:
return 2 * precision * recall / (precision + recall)
except:
return 0.0
5. 返回分类阈值
#通过decision_function可以调整精准率和召回率
decision_scores = log_reg.decision_function(X_test)
- ROC曲线
#分类阈值、TPR和FPR
#分类阈值,即设置判断样本为正例的阈值thr
#如果值高于该阈值,则表示“垃圾邮件”;如果值低于该阈值,则表示“非垃圾邮件”。
#人们往往会认为分类阈值应始终为 0.5,但阈值取决于具体问题,因此您必须对其进行调整
#在sklearn中有一个方法叫:decision_function,即返回分类阈值.
#TPR:预测为1,且预测对了的数量,占真实值为1的数据百分比。很好理解,就是召回率
#FPR:预测为1,但预测错了的数量,占真实值不为1的数据百分比
#TPR和FPR之间是成正比的,TPR高,FPR也高。ROC曲线就是刻画这两个指标之间的关系
#ROC曲线(Receiver Operation Characteristic Cureve),描述TPR和FPR之间的关系。x轴是FPR,y轴是TPR,TPR就是所有正例中,有多少被正确地判定为正;FPR是所有负例中,有多少被错误地判定为正
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
digits = datasets.load_digits()
X = digits.data
y = digits.target.copy()
# 要构造偏斜数据,将数字9的对应索引的元素设置为1,0~8设置为0
y[digits.target==9]=1
y[digits.target!=9]=0
# 使用逻辑回归做一个分类
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
log_reg = LogisticRegression()
log_reg.fit(X_train,y_train)
# 计算逻辑回归给予X_test样本的决策数据值
# 通过decision_function可以调整精准率和召回率
decision_scores = log_reg.decision_function(X_test)
# TPR
def TPR(y_true, y_predict):
tp = TP(y_true, y_predict)
fn = FN(y_true, y_predict)
try:
return tp / (tp + fn)
except:
return 0.0
# FPR
def FPR(y_true, y_predict):
fp = FP(y_true, y_predict)
tn = TN(y_true, y_predict)
try:
return fp / (fp + tn)
except:
return 0.0
fprs = []
tprs = []
# 以0.1为步长,遍历decision_scores中的最小值到最大值的所有数据点,将其作为阈值集合
thresholds = np.arange(np.min(decision_scores), np.max(decision_scores), 0.1)
for threshold in thresholds:
# decision_scores >= threshold 是布尔型向量,用dtype设置为int
# 大于等于阈值threshold分类为1,小于为0,用这种方法得到预测值
y_predict = np.array(decision_scores >= threshold, dtype=int)
#print(y_predict)
# print(y_test)
#print(FPR(y_test, y_predict))
# 对于每个阈值,所得到的FPR和TPR都添加到相应的队列中
fprs.append(FPR(y_test, y_predict))
tprs.append(TPR(y_test, y_predict))
# 绘制ROC曲线,x轴是fpr的值,y轴是tpr的值
plt.plot(fprs, tprs)
plt.show()
9. AUC曲线
#关注是曲线下面的面积, 称为AUC(Area Under Curve)。
#这个AUC是横轴范围(0,1 ),纵轴是(0,1)所以总面积是小于1
#AUC = 1,是完美分类器,采用这个预测模型时,不管设定什么阈值都能得出完美预测。绝大多数预测的场合,不存在完美分类器。
#0.5 < AUC < 1,优于随机猜测。这个分类器(模型)妥善设定阈值的话,能有预测价值
#AUC = 0.5,跟随机猜测一样,模型没有预测价值
#AUC < 0.5,比随机猜测还差;但只要总是反预测而行,就优于随机猜测
from sklearn.metrics import roc_auc_score
roc_auc_score(y_test, decision_scores)
总结:
#F1 Score是精准率和召回率的调和平均值,可以平衡这两个指标。
#又学习了分类阈值、TPR、FPR这三个概念,进而引出ROC来反映分类器的性能。AUC是曲线下面积,用来直观比较模型的好坏
二、线性回归指标评价
简单线性回归的目标
衡量标准是看在测试数据集中y的真实值与预测值之间的差距
- MSE
测试集中的数据量m不同,因为有累加操作,所以随着数据的增加 ,
误差会逐渐积累;因此衡量标准和 m 相关。
为了抵消掉数据量的形象,可以除去数据量,抵消误差
mse_test = np.sum((y_predict - y_test) ** 2) / len(y_test)
mse_test
- RMSE
为了解决量纲的问题,可以将其开方(为了解决方差的量纲问题,将其开方得到平方差)得到均方根误差
from math import sqrt
rmse_test = sqrt(mse_test)
rmse_test
- MAE
之间的距离最小,可以直接相减做绝对值,加m次再除以m,即可求出平均距离,被称作平均绝对误差,在之前确定损失函数时,我们提过,绝对值函数不是处处可导的,因此没有使用绝对值。但是在评价模型时不影响。因此模型的评价方法可以和损失函数不同
mae_test = np.sum(np.absolute(y_predict - y_test)) / len(y_test)
mae_test
- R Square
对于分子来说,预测值和真实值之差的平方和,即使用我们的模型预测产生的错误。
对于分母来说,是均值和真实值之差的平方和,即认为“预测值=样本均值”这个模型(Baseline Model)所产生的错误
因此用1减去较少的错误除以较多的错误,实际上是衡量了我们的模型拟合住数据的地方,即没有产生错误的相应指标。
封装:
mport numpy as np
from math import sqrt
def accuracy_score(y_true, y_predict):
"""计算y_true和y_predict之间的准确率"""
assert y_true.shape[0] != y_predict.shape[0], \
"the size of y_true must be equal to the size of y_predict"
return sum(y_true == y_predict) / len(y_true)
def mean_squared_error(y_true, y_predict):
"""计算y_true和y_predict之间的MSE"""
assert len(y_true) == len(y_predict), \
"the size of y_true must be equal to the size of y_predict"
return np.sum((y_true - y_predict) ** 2) / len(y_true)
def root_mean_squared_error(y_true, y_predict):
"""计算y_true和y_predict之间的RMSE"""
return sqrt(mean_squared_error(y_true, y_predict))
def mean_absolute_error(y_true, y_predict):
"""计算y_true和y_predict之间的MAE"""
assert len(y_true) == len(y_predict), \
"the size of y_true must be equal to the size of y_predict"
return np.sum(np.absolute(y_predict - y_true)) / len(y_predict)
from myAlgorithm.metrics import mean_squared_error
from myAlgorithm.metrics import root_mean_squared_error
from myAlgorithm.metrics import mean_absolute_error
mean_squared_error(y_test, y_predict)
# 输出:24.156602134387438
root_mean_squared_error(y_test, y_predict)
# 输出:4.914936635846635
mean_absolute_error(y_test, y_predict)
# 输出:3.5430974409463873
总结:
线性回归的评价指标与分类的评价指标有很大的不同,本篇介绍了均方误差MSE(预测值与真实值之差的平方和,再除以样本量)、均方根误差RMSE(为了消除量纲,将MSE开方)、平均绝对误差MAE(预测值与真实值之差的绝对值,再除以样本量)、以及非常重要的、效果非常好的R方(因此用1减去较少的错误除以较多的错误,实际上是衡量了我们的模型拟合住数据的地方,即没有产生错误的相应指标)。
##############################################################################################################
@ 2019.11.17 木居居士的机器学习小组 第二周 打卡
安利公益监督学习组织 - 【公众号】数据科学家联盟
https://mp.weixin.qq.com/s/1WWmbLZucz9vIp-4tKKQ5Q
感谢木东大佬、饼干大佬、南头大佬、星空妹砸、Desitiny的无私付出,抱拳ing~