# -*- coding: utf-8 -*-
"""
Created on Wed Jan 9 09:18:49 2019
@author: shenfangyuan
参见:http://scikit-learn.org/stable/modules/model_evaluation.html#log-loss
"""
from sklearn.metrics import log_loss
from sklearn.preprocessing import LabelBinarizer
from math import log
import numpy as np
'''
数据说明:
1,y_pred是3行10列的数据,3行代表3个样本,10列代表该行样本对应于classes中类别的
分类概率, y_pred每行数据(各个类别的预测概率之和)相加和是"1".
2,y_pred的3个行与:y_true = ['1', '4', '5']相对应,代表着该行数据的真实分类标签
他的数据取自于classes中的值.
3,我们通过每行的10个数据,得到分类的预测值.
4,y_pred的每行10个数据,类似于神经网络的10个输出神经元细胞,(相当于10个评委)
这10个输出分别对应在10个"类别轴"上的概率值.我们通常取这10个值中的最大值,
作为分类的预测值,把各行的分类预测值与分类标签y_true对比,求取差异--交叉熵.
1)先求数据在每个"类别轴"的投影值,"预测概率" 向量
2)求概率预测值向量中的最大值,作为该行数据最后所属的分类值.
3)把预测得到的分类与标记标签进行"差异"估计--交叉熵是方法之一!
'''
classes = ['0','1','2','3','4','5','6','7','8','9']
#y_true 是样本集合中,样本的真实标签,其取值数据只能取自labels集合中的元素
y_true = ['1', '4', '5']
#y_pred 样本的预测概率 每行 10个元素,labels也是10个元素.
y_pred = [[0.1, 0.6, 0.3, 0, 0, 0, 0, 0, 0, 0],
[0, 0.3, 0.2, 0, 0.5, 0, 0, 0, 0, 0],
[0.6, 0.3, 0, 0, 0, 0.1, 0, 0, 0, 0]]
# 利用sklearn中的log_loss()函数计算交叉熵
sk_log_loss = log_loss(y_true, y_pred, labels=classes)
print("Loss by sklearn is:%s." %sk_log_loss)
# 利用公式实现交叉熵
# 交叉熵的计算公式网址为:
# http://scikit-learn.org/stable/modules/model_evaluation.html#log-loss
# 对样本的真实标签进行标签二值化
lb = LabelBinarizer() #构造一个LabelBinarizer类对象
lb.fit(classes) #通过类对象,以classes中的数据为参数对类对象进行配置
transformed_labels = lb.transform(y_true) #依照类对象中存储的classes,对y_true进行编码
#transformed_labels是(3,10)的矩阵,one-hot编码,3行对应3个数据,10列对应10个分类类别的概率.
#相当于把y_true进行one-hot编码.
# print(transformed_labels)
N = len(y_true) # 样本个数 N=3
K = len(classes) # 标签个数 K=10
eps = 1e-15 # 预测概率的控制值
#eps = 0.00001 # 预测概率的控制值
Loss = 0 # 损失值初始化
for i in range(N):
for k in range(K):
# 控制预测概率在[eps, 1-eps]内,避免求对数时出现问题
# 这里主要是为了避免出现数值计算问题,如:log(0) 和 log(1)
if y_pred[i][k] < eps:
y_pred[i][k] = eps
if y_pred[i][k] > 1-eps:
y_pred[i][k] = 1-eps
# 多分类问题的交叉熵计算公式
# transformed_labels 是理想标签经过转换后的矩阵,维度也是 (3,10)
Loss -= transformed_labels[i][k]*log(y_pred[i][k])
Loss /= N
print("Loss by equation is:%s." % Loss)
'''
Loss by sklearn is:1.16885263244.
Loss by equation is:1.16885263244.
'''