前言
在机器学习当中KNN算是简单的算法之一,但KNN稳定度是非常不稳定的,主要取决于K的设置,但K不是越大也不是越小越好,所以这就是我们困扰地方之一,还有KNN主要需计算输入资料与现有的标记资料两者的距离,这时候又产生一个问题,当维度越大计算量就越大,但若资料分群很明显使用KNN还是一个不错的方法,往后也可以拿来与其它机器学习合併做为参考。
KNN算法步骤
这里使用二维讲解KNN,它公式很简单,就是计算输入资料与标记资料每个点距离取出K个距离最小值进行投票。这里使用欧式距离。
计算输入资料和标记资料距离。取出K个距离最小值的原始标记。取出标记最多的标记。Numpy实作KNN
程式码
1.创建标记资料与输入资料。
这里分为三群,使用concatenate
将三群资料水平列(axis=0
)合併,real_data
为输入资料。
# initreal_datas1 = np.array(np.random.rand(10, 2) * 5)real_labels1 = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])real_datas2 = np.array(10 + np.random.rand(10, 2) * 5)real_labels2 = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])real_datas3 = np.array(20 + np.random.rand(10, 2) * 5)real_labels3 = np.array([2, 2, 2, 2, 2, 2, 2, 2, 2, 2])# np.appendreal_datas = np.concatenate((real_datas1, real_datas2, real_datas3), axis=0)real_labels = np.concatenate((real_labels1, real_labels2, real_labels3))input_data = np.array([7.5, 7.5])
2.距离函数。
参数:value1为标籤资料,value2为输入资料。value1
大小为[N, 2],value2
大小为[2],这里value2
会往下自动扩展到[N, 2],计算完每个点距离后,设置axis=1
垂直行加总,最后结果为与每个标记资料的距离。
注:若需要预测多笔则可使用扩展或一开始设置三维标记资料再用扩展。
def distance(value1, value2): return np.sum((value1 - value2) ** 2, axis=1)
预测函数。参数:real_data
和real_label
为标籤资料,input_data
为输入资料,k
为取几个投票数。
使用argpartition
得到索引由小到大,排序至k
个并取出索引放入real_label
取出真实标籤。而取出标籤后要进行投票取出哪个标籤最多,这时候可使用迴圈方法(注解部分),或使用one-hot方法(因可直接用sum指令水平列往上加即是投票结果)。
这里使用one-hot,首先宣告一个数值为0、大小为[K, N群]的阵列,再将one_hot_labels
放入索引位置指派1,结果即是one-hot,在使用sum
设置axis=0
往上加总,结果为投票结果,最后取出最大值的索引位置即是预测结果。
def predict(real_data, real_label, input_data, k): distances = distance(real_data, input_data) near_labels = real_label[np.argpartition(distances, np.arange(0, k, 1))[0:k]] one_hot_labels = np.zeros((k, class_type)) one_hot_labels[np.arange(k), near_labels] = 1 vote_labels = np.sum(one_hot_labels, axis=0) #vote_labels = np.zeros([class_type]) #for index in range(class_type - 1) : # vote_labels[index] = np.sum(near_labels == index) return np.argmax(vote_labels)
绘图get_predict_color
输入为标籤,回传为绘图的颜色和形状。
def get_predict_color(type): if type == 0: return 'yo' elif type == 1: return 'ro' else: return 'bo' plt.plot(real_datas1[:, 0], real_datas1[:, 1], 'yo')plt.plot(real_datas2[:, 0], real_datas2[:, 1], 'ro')plt.plot(real_datas3[:, 0], real_datas3[:, 1], 'bo')plt.plot(input_data[0], input_data[1], get_predict_color(predict_type))plt.show()
结果图
预测图为第二类,有时候会第一类。
Tensorflow实作KNN
两者非常相似,很多只差在宣告或API不同,但Tensorboard
能方便提供可视化流程和数据给我们参考,所以如果需要给别人看流程或者数据可以使用Tensorflow
来实作。
程式码
1.创建标记资料与输入资料。
这里分为三群,使用concat
将三群资料水平列(axis=0
)合併,real_data
为输入资料。
real_datas1 = tf.random_uniform([10, 2], minval=0, maxval=5, name="real_datas1")real_labels1 = tf.constant([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], name="real_labels1")real_datas2 = tf.random_uniform([10, 2], minval=10, maxval=15, name="real_datas2")real_labels2 = tf.constant([1, 1, 1, 1, 1, 1, 1, 1, 1, 1], name="real_labels2")real_datas3 = tf.random_uniform([10, 2], minval=20, maxval=25, name="real_datas3")real_labels3 = tf.constant([2, 2, 2, 2, 2, 2, 2, 2, 2, 2], name="real_labels3")real_datas = tf.concat([real_datas1, real_datas2, real_datas3], axis=0, name="real_datas")real_labels = tf.concat([real_labels1, real_labels2, real_labels3], axis=0, name="real_labels")input_data = tf.constant([7.5, 7.5], dtype=tf.float32, name="input_data")
初始化数据。
2.距离函数。
参数:value1为标籤资料,value2为输入资料。real_datas
大小为[N, 2],input_data
大小为[2],使用subtract
计算矩阵减法,input_data
会自动扩展至[N, 2],计算完每个点距离后,设置axis=1
垂直行加总,最后结果为与每个标记资料的距离。
注:若需要预测多笔则可使用扩展或一开始设置三维标记资料再用扩展。
def distance(real_datas, input_data): diff = tf.subtract(real_datas, input_data) ** 2 row_sum = tf.reduce_sum(diff, axis=1) return row_sum
距离函数。
参数:real_datas
和real_labels
为标籤资料,input_data
为输入资料,k
为取几个投票数。
使用top_k
得到k
个由小到大(使用negative
,top_k
预设大到小)的索引值(indices
),使用gather
取出索引对应的真实标籤。使用one_hot_labels
取得one-hot,在使用sum
设置axis=0
往上加总,结果为投票结果,最后取出最大值的索引位置即是预测结果。
def predict(real_datas, real_labels, input_data, k): distances = distance(real_datas, input_data) near_indexs = tf.nn.top_k(tf.negative(distances), k).indices near_labels = tf.gather(real_labels, near_indexs, name="near_labels") one_hot_labels = tf.one_hot(indices=near_labels, depth=class_type, on_value=1, off_value=0, name="one_hot_labels") count_labels = tf.reduce_sum(one_hot_labels, axis=0) return tf.argmax(count_labels)
预测函数。
plt.plot(session.run(real_datas1[:, 0]), session.run(real_datas1[:, 1]), 'yo')plt.plot(session.run(real_datas2[:, 0]), session.run(real_datas2[:, 1]), 'ro')plt.plot(session.run(real_datas3[:, 0]), session.run(real_datas3[:, 1]), 'bo')plt.plot(session.run(input_data[0]), session.run(input_data[1]), get_predict_color(predict_type))plt.show()
结果图
预测图为第一类,有时候会第二类。
结语
参考的东西其实算是之前上人工智慧课程老师介绍的,但不知该如何打所以省略,下次介绍计算方式有些地方很像的KMean
,若有问题或错误欢迎留言或私讯。
参考网址与书籍
[1] https://www.tensorflow.org/api_docs/python/tf