Confusion matrix using numpy.bincount.

1. np.bincount函数

np.bincount用于统计一个非负数组中元素的出现次数。函数格式如下:

import numpy as np
np.bincount(x, weights=None, minlength=None)

通常默认数组$x$的最小值为$0$,若其最大值为$n$,则会返回长度为$n+1$的数组,其索引$i$表示数值$i$在数组$x$中出现的次数:

# x中最大的数为7,因此bin的数量为8,其索引值为0->7
x = np.array([0, 1, 1, 3, 2, 1, 7])
# 索引0出现了1次,索引1出现了3次......索引7出现了1次
np.bincount(x)
#输出结果为:array([1, 3, 1, 1, 0, 0, 0, 1])

参数weights指定了数组$x$每个位置的权重(默认权重为$1$),如果在位置$i$出现值$n$,则有out[n]+=weights[i]而不是out[n]+=1

w = np.array([0.3, 0.5, 0.2, 0.7, 1., -0.6])
# x中最大的数为4,因此bin的数量为5,其索引值为0->4
x = np.array([2, 1, 3, 4, 4, 3])
# 索引0 -> 0
# 索引1 -> w[1] = 0.5
# 索引2 -> w[0] = 0.3
# 索引3 -> w[2] + w[5] = 0.2 - 0.6 = -0.4
# 索引4 -> w[3] + w[4] = 0.7 + 1 = 1.7
np.bincount(x, weights=w)
# 输出结果为:array([ 0. ,  0.5,  0.3, -0.4,  1.7])

参数minlength指定了bin的最小长度。其最小长度不会低于数组最大值加$1$:

# x中最大的数为3,因此bin的数量为4,其索引值为0->3
x = np.array([3, 2, 1, 3, 1])
# bin的默认数量为4,若指定参数为7,则bin的数量为7,其索引值为0->6
np.bincount(x, minlength=7)
# 输出结果为:array([0, 2, 1, 2, 0, 0, 0])

# bin的默认数量为4,若指定参数为1,指定数量小于默认值,索引值还是0->3
np.bincount(x, minlength=1)
# 输出结果为:array([0, 2, 1, 2])

2. 使用np.bincount计算混淆矩阵

混淆矩阵是分类任务的常用评估方法,对于多分类任务,混淆矩阵会统计每个类别的预测情况。一个具有$3$个类别的混淆矩阵表示如下

\[\begin{array}{l|ccc} \text{真实情况\预测结果} & \text{类别1} & \text{类别2} & \text{类别3} \\ \hline \text{类别1} & a & b & c \\ \text{类别2} & d & e & f \\ \text{类别3} & g & h & i \\ \end{array}\]

注意到真实类别为$i$,预测类别为$j$的样本被统计到第$i$行第$j$列,若将混淆矩阵拉直成一个行向量,则对应索引位置为$n*i+j$。

若预测数组为pred,标签数组为label,类别数为n。则数组n*label+pred存储了混淆矩阵的索引值。

import numpy as np

def genConfusionMatrix(pred, label, n):
    '''
    Parameters
    ----------
    pred : 预测数组.
    label : 标签数组.
    n : 类别数(不包括背景).
    '''
    return np.bincount(n*label+pred, minlength=n**2).reshape(n, n)

pred = np.array([0,1,0,2,1,0,2,2,1])
label = np.array([0,2,0,2,1,0,0,2,1])
print(genConfusionMatrix(pred, label, 3))

###
[[3 0 1]
 [0 2 0]
 [0 1 2]]
###