Python 如何创建k-最近邻分类置信度估计的彩色映射 我想要的是:

Python 如何创建k-最近邻分类置信度估计的彩色映射 我想要的是:,python,algorithm,numpy,matplotlib,Python,Algorithm,Numpy,Matplotlib,将我的简单分类算法(见下文)的结果显示为python中的colormap(数据为2D),其中每个类都分配了一种颜色,2D贴图上任何位置的预测置信度与与与类预测相关的颜色饱和度成正比。下面的图片说明了我对二进制(两类问题)的要求,其中红色部分可能表示对类1有很强的信心,而蓝色部分表示对类2有信心。中间的颜色表示两者的不确定性。显然,我希望颜色方案能够推广到多个类,因此我需要许多颜色,然后比例将从白色(不确定)变为与类相关的非常丰富多彩的颜色 一些示例代码: 我的示例代码只使用了一个简单的kNN算

将我的简单分类算法(见下文)的结果显示为python中的colormap(数据为2D),其中每个类都分配了一种颜色,2D贴图上任何位置的预测置信度与与与类预测相关的颜色饱和度成正比。下面的图片说明了我对二进制(两类问题)的要求,其中红色部分可能表示对类1有很强的信心,而蓝色部分表示对类2有信心。中间的颜色表示两者的不确定性。显然,我希望颜色方案能够推广到多个类,因此我需要许多颜色,然后比例将从白色(不确定)变为与类相关的非常丰富多彩的颜色

一些示例代码: 我的示例代码只使用了一个简单的kNN算法,其中允许最近的k个数据点对地图上的新点类进行“投票”。预测的置信度仅由投票的k中获胜班级的相对频率给出。我还没有处理过关系,我知道这种方法有更好的概率版本,但我只想可视化我的数据,向查看者显示类位于2D平面特定部分的可能性

import numpy as np
import matplotlib.pyplot as plt


# Generate some training data from three classes
n = 100 # Number of covariates (sample points) for each class in training set. 
mean1, mean2, mean3 = [-1.5,0], [1.5, 0], [0,1.5]
cov1, cov2, cov3 = [[1,0],[0,1]], [[1,0],[0,1]], [[1,0],[0,1]]
X1 = np.asarray(np.random.multivariate_normal(mean1,cov1,n))
X2 = np.asarray(np.random.multivariate_normal(mean2,cov2,n))
X3 = np.asarray(np.random.multivariate_normal(mean3,cov3,n))


plt.plot(X1[:,0], X1[:,1], 'ro', X2[:,0], X2[:,1], 'bo', X3[:,0], X3[:,1], 'go' )

plt.axis('equal'); plt.show() #Display training data


# Prepare the data set as a 3n*3 array where each row is a data point and its associated class
D = np.zeros((3*n,3))
D[0:n,0:2] = X1; D[0:n,2] = 1
D[n:2*n,0:2] = X2; D[n:2*n,2] = 2
D[2*n:3*n,0:2] = X3; D[2*n:3*n,2] = 3

def kNN(x, D, k=3):
    x = np.asarray(x)
    dist = np.linalg.norm(x-D[:,0:2], axis=1)
    i = dist.argsort()[:k] #Return k indices of smallest to highest entries
    counts = np.bincount(D[i,2].astype(int))
    predicted_class = np.argmax(counts) 
    confidence = float(np.max(counts))/k
    return predicted_class, confidence 

print(kNN([-2,0], D, 20))

因此,可以为二维平面中的每个点计算两个数字

  • 置信度(0..1)
  • 类(整数)
一种可能是计算您自己的RGB贴图,并使用
imshow
显示它。像这样:

import numpy as np
import matplotlib.pyplot as plt

# color vector with N x 3 colors, where N is the maximum number of classes and the colors are in RGB
mycolors = np.array([
  [ 0, 0, 1],
  [ 0, 1, 0],
  [ 1, 0, 1],
  [ 1, 1, 0],
  [ 0, 1, 1],
  [ 0, 0, 0],
  [ 0, .5, 1]])

# negate the colors
mycolors = 1 - mycolors 

# extents of the area
x0 = -2
x1 = 2
y0 = -2
y1 = 2

# grid over the area
X, Y = np.meshgrid(np.linspace(x0, x1, 1000), np.linspace(y0, y1, 1000))

# calculate the classification and probabilities
classes = classify_func(X, Y)
probabilities = prob_func(X, Y)

# create the basic color map by the class
img = mycolors[classes]

# fade the color by the probability (black for zero prob)
img *= probabilities[:,:,None]

# reverse the negative image back
img = 1 - img

# draw it
plt.imshow(img, extent=[x0,x1,y0,y1], origin='lower')
plt.axis('equal')

# save it
plt.savefig("mymap.png")
制作负颜色的诀窍就是让数学更容易理解。代码当然可以写得更密集

我创建了两个非常简单的函数来模拟分类和概率:

def classify_func(X, Y):
    return np.round(abs(X+Y)).astype('int')

def prob_func(X,Y):
    return 1 - 2*abs(abs(X+Y)-classify_func(X,Y))
前者给出了给定区域的整数值从0到4,后者给出了平滑变化的概率

结果是:

如果您不喜欢颜色向零概率方向褪色的方式,您可能总是会创建一些非线性,这是与概率相乘时应用的


这里函数
classify_func
prob_func
有两个数组作为参数,第一个是要计算值的X坐标,第二个是Y坐标。如果基础计算完全矢量化,那么这种方法效果很好。对于问题中的代码,情况并非如此,因为它只计算单个值

在这种情况下,代码会略有变化:

x = np.linspace(x0, x1, 1000)
y = np.linspace(y0, y1, 1000)
classes = np.empty((len(y), len(x)), dtype='int')
probabilities = np.empty((len(y), len(x)))
for yi, yv in enumerate(y):
    for xi, xv in enumerate(x):
    classes[yi, xi], probabilities[yi, xi] = kNN((xv, yv), D)
此外,由于您的置信度估计值不是0..1,因此需要对其进行缩放:

probabilities -= np.amin(probabilities)
probabilities /= np.amax(probabilities)
完成此操作后,地图的范围应如下所示-4,-4..4,4(根据颜色地图:绿色=1,品红色=2,黄色=3):


矢量化还是不矢量化-这就是问题所在

这个问题不时出现。网络上有很多关于矢量化的信息,但是快速搜索并没有发现任何简短的摘要,我在这里给出一些想法。这是一个相当主观的问题,所以一切都代表了我的拙见。其他人可能有不同的意见

有三个因素需要考虑:

  • 演出
  • 易读性
  • 内存使用
通常(但并非总是)矢量化会使代码更快、更难理解并消耗更多内存。内存使用通常不是一个大问题,但对于大型阵列,这是一个需要考虑的问题(数百兆兆通常是可以的,千兆字节是麻烦的)

撇开琐碎的情况不谈(元素简单运算、简单矩阵运算),我的方法是:

  • 编写没有矢量化的代码并检查它是否工作
  • 剖析代码
  • 如果需要和可能,对内部循环进行矢量化(1D矢量化)
  • 创建二维矢量化(如果简单)
例如,逐像素图像处理操作可能会导致以一维矢量化(针对每行)结束的情况。然后,内循环(对于每个像素)是快速的,而外循环(对于每行)实际上并不重要。如果代码不尝试对所有可能的输入维度都可用,那么它看起来可能会简单得多

我是一个非常糟糕的算法专家,在更复杂的情况下,我喜欢对照非矢量化版本验证我的矢量化代码。因此,我几乎总是先创建非矢量化代码,然后再对其进行优化

有时矢量化不能提供任何性能优势。例如,方便的函数
numpy.vectorize
几乎可以用于对任何函数进行矢量化,但其文档说明:

提供矢量化功能主要是为了方便,而不是为了性能。该实现本质上是一个for循环

(这个函数也可以在上面的代码中使用。我选择循环版本是为了让不太熟悉
numpy
的人看得清楚)

只有在底层向量化函数更快的情况下,向量化才能提供更高的性能。他们有时是,有时不是。只有分析和经验才能说明问题。此外,并非总是需要对所有内容进行矢量化。您可能有一个图像处理算法,它具有矢量化和逐像素操作。有
numpy.vectorize
非常有用

我会尝试将上面的kNN搜索算法矢量化到至少一个维度。没有条件代码(它不是一个show-stopper,但会使事情复杂化),而且算法相当简单。内存消耗将增加,但一维矢量化并不重要


在这个过程中,你可能会注意到,n维的泛化并不复杂。如果内存允许,那么就这样做。

非常感谢!这看起来很有希望。你能给我个建议吗