簡體   English   中英

如何為k最近鄰分類創建置信度估計的顏色圖

[英]How to create colormap of confidence estimates for k-Nearest Neighbor Classification

我想要的是:

要將我的簡單分類算法的結果(如下所示)顯示為python中的顏色圖(數據為2D),其中為每個類別分配了一種顏色,並且2D地圖上任意位置的預測可信度與飽和度成比例與類別預測相關的顏色。 下圖顯示了我對二元(兩類問題)的要求,其中紅色部分可能表示對1類有較強的信心,而藍色部分可能表示對2類具有說服力。中間的顏色表明這兩種類型都存在不確定性。 顯然,我希望配色方案可以推廣到多個類別,因此我將需要多種顏色,然后比例會從白色(不確定性)變為與某個類別相關的非常鮮艷的顏色。

插圖http://www.nicolacarlon.it/out.png

一些示例代碼:

我的示例代碼僅使用一種簡單的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))

因此,您可以為2D平面中的每個點計算兩個數字

  • 置信度(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_funcprob_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):

kNN圖


向量化還是不向量化-這就是問題

這個問題有時會彈出。 網絡上有很多有關矢量化的信息,但是由於快速搜索沒有發現任何簡短的摘要,因此我在這里給出一些想法。 這是一個主觀的問題,因此所有內容都代表我的拙見。 其他人可能有不同的意見。

要考慮三個因素:

  • 性能
  • 易讀性
  • 內存使用

通常(但並非總是),向量化可使代碼更快,更難以理解,並占用更多內存。 內存使用通常不是一個大問題,但是對於大型數組來說,這是一個值得思考的問題(通常可以使用數百兆,而麻煩的是千兆字節)。

除了瑣碎的情況(元素方式的簡單操作,簡單的矩陣操作),我的方法是:

  • 編寫沒有向量化的代碼並檢查其是否有效
  • 分析代碼
  • 如果需要並可能的話,對內部循環進行矢量化處理(一維矢量化)
  • 如果簡單,則創建2D矢量化

例如,逐個像素的圖像處理操作可能會導致我最終以一維矢量化(針對每一行)的情況出現。 然后,內循環(用於每個像素)很快,而外循環(用於每一行)並不重要。 如果該代碼未嘗試在所有可能的輸入尺寸中使用,則看起來可能會簡單得多。

我是一個糟糕的算法專家,在更復雜的情況下,我想對照非矢量化版本來驗證我的矢量化代碼。 因此,我幾乎總是先創建非矢量化的代碼,然后再對其進行優化。

有時矢量化不會提供任何性能優勢。 例如,方便的函數numpy.vectorize可用於向量化任何函數,但其​​文檔指出:

提供矢量化功能主要是為了方便,而不是為了提高性能。 該實現實質上是一個for循環。

(該函數也可以在上面的代碼中使用。出於對易懂numpy不太熟悉的人的考慮,我選擇了循環版本。)

僅當基礎矢量化功能更快時,矢量化才能提供更高的性能。 他們有時是,有時不是。 只有剖析和經驗會證明一切。 同樣,並非總是必須對所有內容進行矢量化處理。 您可能具有同時進行矢量化和逐像素運算的圖像處理算法。 那里有numpy.vectorize非常有用。

我會嘗試將至少k維以上的kNN搜索算法向量化。 沒有條件代碼(它不會成為秀場停止者,但會使事情變得復雜),並且該算法相當簡單。 內存消耗將增加,但是使用一維矢量化沒關系。

沿途您可能會發現n維概括並不復雜。 然后在內存允許的情況下執行此操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM