这次实验主要是进行模型评估与选择,采用混淆矩阵及其P-R曲线,ROC曲线,前四个例子是二分类的问题,第五个是多分类的问题。
这里讲讲对部分关键代码的理解:
这里是实现计算TN,即真反例个数:在确保实际值与预测值长度相等的条件下,只有实际类别和预测类别都为0时才计入。FN,TP,FP实现逻辑类似,部分不同。
这里是计算查准率,即P:根据公式,查准率等于真正例/(真正例+假正例)。召回率类似,只是等于真正率/(真正率+假反例)。
这里是根据决策分数值为5来进行分类,即大于5则为1,小于5则为0,并根据预测值和实际值得到混淆矩阵。实验中多处使用不同的决策分数值来预测,进而观察P,R值来判断模型好坏。
这里是根据不同的决策分数值来计算查准率和召回率,得到多组值便于画出P-R图,可以更加值观的看出变化趋势以及关系。ROC实现类似,仅求值目标不同。
下列求值默认处理二分类问题,对于多分类问题,我们还得加上参数:average=“micro”。
下图是查准率以及召回率随决策分数值的变化情况:
蓝线表示查准率,可以看出,随决策分数值的增加,即阈值的严格化,查准率逐渐上升至不变。
黄线表示查全率,可以看出,随决策分数值的增加,即阈值的严格化,查全率逐渐下降。
两条线的交点称为平衡点,即查准率等于召回率,此时这个点对应的模型具有不错的性能。
下图为P-R图,即查准率为纵坐标,召回率为横坐标,若其中有多条曲线,则线条与坐标系包围的面积越大,说明模型的性能越好,其中越接近(1,1),性能越好。当为一条横线时,表示此模型无区分类别能力。
下图为ROC曲线,即真正率为纵坐标,假正率为横坐标:在此图中,AUC,即曲线下的面积越大,说明模型的性能越好,越接近(0,1),表示性能越好。且图中y=x直线表示无鉴别能力。
下图是多分类矩阵混淆矩阵的可视化结果:根据混淆矩阵对应的值来呈现不同的亮度,可以看出对角线较亮,表明查准率较好。
下图是混淆矩阵每一个数占每一行总数的百分比,越亮表示错误越多。
1、混淆矩阵是机器学习中总结分类模型预测结果的情形分析表,以矩阵形式将数据集中的记录按照真实的类别与分类模型预测的类别判断两个标准进行汇总。其中矩阵的行表示真实值,矩阵的列表示预测值,混淆矩阵能够帮助我们迅速可视化各种类别误分为其它类别的比重,这样能够帮我们调整后续模型,比如一些类别设置权重衰减!
2、在一些实验分析中,可以列出混淆矩阵,行和列均为label种类,可以通过该矩阵验证自己model预测复杂label的能力强于其他model,只要自己model复杂label误判为其它类别比其他model误判的少,就可以说明自己model预测复杂label的能力强于其他model。
PlayML中求混淆矩阵及其相关指标代码:
def accuracy_score(y_true, y_predict) :
"""计算y_true和y_predict之间的准确率"""
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) / 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_true - y_predict)) / len(y_true)
def r2_score(y_true, y_predict) :
"""计算y_true和y_predict之间的R Square"""
return 1 - mean_squared_error(y_true, y_predict) / np.var(y_true)
def TN(y_true, y_predict) :
assert len(y_true) == len(y_predict)
return np.sum((y_true == 0) & (y_predict == 0))
def FP(y_true, y_predict) :
assert len(y_true) == len(y_predict)
return np.sum((y_true == 0) & (y_predict == 1))
def FN(y_true, y_predict) :
assert len(y_true) == len(y_predict)
return np.sum((y_true == 1) & (y_predict == 0))
def TP(y_true, y_predict) :
assert len(y_true) == len(y_predict)
return np.sum((y_true == 1) & (y_predict == 1))
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)]
] )
def precision_score(y_true, y_predict) :
assert len(y_true) == len(y_predict)
tp = TP(y_true, y_predict)
fp = FP(y_true, y_predict)
try :
return tp / (tp + fp)
except :
return 0.0
def recall_score(y_true, y_predict) :
assert len(y_true) == len(y_predict)
tp = TP(y_true, y_predict)
fn = FN(y_true, y_predict)
try :
return tp / (tp + fn)
except :
return 0.0
def f1_score(y_true, y_predict) :
precision = precision_score(y_true, y_predict)
recall = recall_score(y_true, y_predict)
try :
return 2. * precision * recall / (precision + recall)
except :
return 0.
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.
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.