P某的备忘录

用几分钟就可以了解的人工神经网络原理—初级网络— K-近邻网络篇

用几分钟就可以了解的人工神经网络原理—初级网络— K-近邻网络篇

封面图片 credit: from Medium @ Shubham Panchal
在上期,我们入门了神经网络的基本定义。从本期开始本P将逐步以基本的神经网络入手,介绍具体的网络定义。在本期,本P将会介绍 K-NN(k-nearest neighbors algorithm), 亦即 K-近邻方法。

名词解释

以下通过一个西瓜的故事来解释本篇中涉及到的名词:

如果我们想要预测的参数不连续,是离散值,例如“好瓜”“坏瓜”,此类学习任务称为分类;如果想要预测的是连续值,例如某种西瓜在某时刻的成熟度是0.95、0.37等等,此类学习任务称为回归
学得模型后,使用其进行预测的过程称为测试,被预测的样本成为测试样本。例如在学得ff后,对测试例xx,可得到其预测标记y=f(x)y=f(x)

根据训练数据是否拥有标记信息,学习任务可大致分为两大类:监督学习非监督学习。监督学习其实就是我们对输入样本经过模型训练后,有明确的预期输出,非监督学习,就是我们对输入样本经过模型训练后得到什么输出完全没有预期。结合西瓜的例子,监督学习就是我们知道经过模型训练后,会分为好瓜或者坏瓜,而非监督学习则会将西瓜分为为几种我们之前没有明确定义的瓜,如“浅色瓜”“外地瓜”。

KNN 是什么?

模式识别领域中,最近邻居法(KNN算法,又译K-近邻算法)是一种用于分类和回归的非参数统计方法。在这两种情况下,输入包含特征空间(Feature Space)中的k个最接近的训练样本。
K-NN是一种基于实例的学习,或者是局部近似和将所有计算推迟到分类之后的惰性学习。k-近邻算法是所有的机器学习算法中最简单的之一。

——来自维基百科

上面的东西用人话讲就是一类分类算法,先划一个圈,圈里面满足指标多的就分类为该大类。这么一句话显然不够完全描述这个算法的全貌,以下是实现过程。
示意图

代码实现

以下代码在 python 3.7 下编译通过。训练数据集在此。请按照原始程序中的代码路径存放数据集或更改对应路径。

import pandas as pd
import numpy as np
import math
import operator


TRAIN_FILE_PATH = './data/train.csv' #训练文件路径
TEST_FILE_PATH = './data/test.csv' #测试文件路径
DIRECTION_FILE_PATH = './data/trainDirection.csv' 
FINAL_TEST_FILE_k1 = './results/testingk1.csv'
FINAL_TEST_FILE_k3 = './results/testingk3.csv'
FINAL_TEST_FILE_k5 = './results/testingk5.csv'
FINAL_TEST_FILE_k10 = './results/testingk10.csv'

train_data_frame = []
test_data_frame = []

'''
   读取相关数据
'''
def loadData(filePath):
    dataFrame = pd.read_csv(filePath)
    return dataFrame

'''
    添加训练数据集的位置参数
'''
def processData(df):
    directions_df =  pd.read_csv(DIRECTION_FILE_PATH)
    df['Direction'] = directions_df['Direction']
    #print(df.head())
    return df

'''
    将数据转换为矩阵形式
'''
def transformTrainingData(train_data_frame):
    trainings= []
    for index, row in train_data_frame.iterrows():
        test_row = [round(row[0], 3), round(row[1], 3), row[2]]
        trainings.append(test_row)
    return trainings

'''
 计算欧氏距离
'''
def euclidianDistance(sample1, sample2, length):
    distance = 0
    for x in range(length):
        distance += pow(sample1[x] - sample2[x], 2)
    return math.sqrt(distance)

'''
    获取某数据周围特征点的数据
'''
def getNeighbors(train_set, test_sample, k):
    distances = []
    neighbors = []
    length = len(test_sample - 1)

    for x in range(len(train_set)):
        dist = euclidianDistance(test_sample, train_set[x], length)
        distances.append((train_set[x], dist))

    distances.sort(key=operator.itemgetter(1))

    for x in range(k):
        neighbors.append(distances[x][0])

    return neighbors

'''
    返回测试点数据分类值
'''
def getResponse(neighbors):
	classVotes = {}
	for x in range(len(neighbors)):
		response = neighbors[x][-1]
		if response in classVotes:
			classVotes[response] += 1
		else:
			classVotes[response] = 1
	sortedVotes = sorted(classVotes.items(), key=operator.itemgetter(1), reverse=True)
	return sortedVotes[0][0]


'''
    计算准确度
'''
def getAccuracy(testSet, predictions):
	correct = 0
	for x in range(len(testSet)):
		if testSet[x] == predictions[x]:
			correct += 1
	return round((correct/float(len(testSet))) * 100.0, 3)


'''
主函数
'''
def knn(k, path, test_data, train_data, actual_test_data):
    print('*******************************************')
    print('************    K = ', k , '  ******************')
    print('*******************************************')
    copy_of_test_data = test_data.copy()
    copy_of_train_data = train_data
    predictions = []

    print('--> Calculating KNN...')
    for index, test_sample in test_data.iterrows():
        #print(test_sample.values[0], ', ', test_sample.values[1])
        neighbors = getNeighbors(copy_of_train_data, test_sample, k)
        neighbors_prediction = getResponse(neighbors)
        predictions.append(neighbors_prediction)

    print('--> Writing predictions...')
    copy_of_test_data['Direction'] = predictions
    copy_of_test_data.to_csv(path, float_format='%.3f')
    print('--> Calculating Accuracy...')
    accuracy = getAccuracy(actual_test_data, copy_of_test_data['Direction'].values)
    print('Accuracy = ', accuracy, '%')

#############################################################################################
## 数据预处理
train_data_frame  = processData(loadData(TRAIN_FILE_PATH))
training_data = transformTrainingData(train_data_frame)
test_data_frame = loadData(TEST_FILE_PATH)


actual_test_result = pd.read_csv('./data/testing.csv')['Direction'].values

print('Training data: ', train_data_frame.shape[0] ,'samples.')
print('Testing data: ', test_data_frame.shape[0], 'samples.')

knn(1, FINAL_TEST_FILE_k1, test_data_frame, training_data, actual_test_result)
knn(3, FINAL_TEST_FILE_k3, test_data_frame, training_data, actual_test_result)
knn(5, FINAL_TEST_FILE_k5, test_data_frame, training_data, actual_test_result)
knn(10, FINAL_TEST_FILE_k10, test_data_frame, training_data, actual_test_result)

############################################################################
################################### 输出实例 ##################################
'''
(py37) [Path-Redacted] python main.py
Training data:  998 samples.
Testing data:  252 samples.
*******************************************
************    K =  1   ******************
*******************************************
--> Calculating KNN...
--> Writing predictions...
--> Calculating Accuracy...
Accuracy =  100.0 %
*******************************************
************    K =  3   ******************
*******************************************
--> Calculating KNN...
--> Writing predictions...
--> Calculating Accuracy...
Accuracy =  76.19 %
*******************************************
************    K =  5   ******************
*******************************************
--> Calculating KNN...
--> Writing predictions...
--> Calculating Accuracy...
Accuracy =  69.841 %
*******************************************
************    K =  10   ******************
*******************************************
--> Calculating KNN...
--> Writing predictions...
--> Calculating Accuracy...
Accuracy =  64.683 %
'''

后记

整个这么一套下来本P意外的发现数据处理反而变成了大问题,算法的实现反倒问题不大,在翻了几页 pandas 的 docs 之后最终还是搞定了。看来以后也要详细看一下数据预处理。

当然了,这个算法还是很简单的,现在早已被集成在 sklearn 里面了,一句话就可以解决的事情。但为了更好的解释这个算法执行的过程,本P还是全部实现了一遍。但更重要的还是数据预处理。

参考

[1]: Altman, N. S. An introduction to kernel and nearest-neighbor nonparametric regression. The American Statistician. 1992, 46 (3): 175–185. doi:10.1080/00031305.1992.10475879. 原论文地址

Powered by Gridea. CopyRight 2018-2020 MrPeterJin's Media Dept.