实现细节
-
函数_knn()
partial为functools中的函数,可以实现参数的分步传递
from functools import partial def substract(x,y): return x-y f = partial(substract,4)#把4传递给x f(10) #把10传递给y,最终结果为-6
argpartition实现第k个元素为它最终的排序位置,前面的元素比第k个元素小,及第k个元素为第k小的元素,前面的元素均比它小,该函数返回的是索引。
-
函数_predict()
topk_ind = self._knn(x),与x距离排在前k为的索引
topk_y = self.Y[topk_ind],取得响应的目标值
return np.argmax(np.bincount(topk_y)),返回topk_y中出现最多次的topk_y
# bincount() x=np.array([1,1,2,3,0,5]) np.bincount(x) # array[1,2,1,1,0,1] # 上面数组中的第i个位置为k,即i在原数组中有k个,因为原数组中没有4,故上面数组第4个位置为0
-
关于np中的axis
axis=i,即第i维是未定参数,如一个x[2,3]的矩阵,如果对axis=1进行某种操作,相当于将第0维确定的值进行操作,即:x[0,:]和x[1,:]作为形参传递
a=np.ones(3,4) np.sum(a,axis=1) # Out[6]: array([4., 4., 4.]) # 相当于依次对a[0,:],a[1,:],a[2,:]进行求和 np.sum(a,axis=0) # Out[7]: array([3., 3., 3., 3.])
class KNN:
def __init__(self, k=1, distance_func="l2"):
self.k = k
if distance_func == 'l2':
self.distance_func = lambda x, y: np.linalg.norm(x - y)
else:
self.distance_func = distance_func
def _knn(self, x):
dis = np.apply_along_axis(partial(self.distance_func, y=x), axis=-1, arr=self.X)
topk_ind = np.argpartition(dis, self.k)[:self.k]
return topk_ind
def _predict(self, x):
topk_ind = self._knn(x)
topk_y = self.Y[topk_ind]
return np.argmax(np.bincount(topk_y))
def fit(self, X, Y):
self.X = X
self.Y = Y
self.k = min(self.k, len(self.X))
def predict(self, X):
return np.apply_along_axis(self._predict, axis=-1, arr=X)