knn方法预测怀孕,KNN原理简单代码

knn算法即: K-近邻算法(K Nearest Neighborhood),物以类聚人以群分,这是一种根据你的邻居,对你进行分类的方法。

knn方法属于监督学习方法,其原理是:

      如果一个样本在特征空间中的K个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。K为人为设定的超参数

提到远近就离不开距离,在学习knn算法之前,建议先复习一下闵可夫斯基距离,数学部分可以参照西瓜书,或李航博士的统计学原理。

在本案例中,我们使用的是欧式距离,当闵可夫斯基距离中的P项为2时,即代表欧氏距离(可理解为两点间的直线距离)。

在这个案例中,需要用到的包包括:numpy,pandas,skicit-learn, Counter

# 导入相关工具包
import pandas
import numpy as np
from collections import Counter

# 读取训练数据 特征部分(机器人传感器收集的112个顾客气色,气味,脉象,体温等特征)
# 以.values最终取出来的是numpy的形式
x = pandas.read_csv('train_X.csv').values
# print(f'我是test_x:{x}')
# print(np.mean(x),np.std(x))

# 读取训练数据 实际结果部分(上述112位顾客真实的怀孕状态,0表示女娃,1表示男孩,2表示没有怀孕)
y = pandas.read_csv('train_y.csv')
# 通过np.array()转换,也可把DataFrame格式转换成array(numpy)
y = np.array(y)

"""
此部分为knn的原理代码,首先计算一个待预测点到所有已知点的距离,封装成一个方法
调用上述封装的方法,得到所有待预测点到已知点的距离
对距离进行排序
"""
class knn_qingdaifu(object):

    def fit(self,x,y,k=5):
        self.k = k
        self.x = x
        self.y = y

    # 多预测点到所有训练点的过程
    def predict(self,X):
        """
        调用单点的函数,生成新的result列表
        :param X:
        :return:
        """
        self.X = X
        result = [self.oneResult(self.X[i]) for i in range(self.X.shape[0])]
        return result



    # 一个预测点到所有训练点的过程
    def oneResult(self,x_test):
        """
        计算一个点到所有点的距离:
        1.用到了范式:np.linalg.norm;
        2.用到了计算器Counter函数(Counter);
        :param x_test:
        :return:
        """
        # 计算一个点到所有已知点的欧氏距离  列表式
        """
        列表式出现了一个bug就是self.y[i][0]:通过前一页的打印可以发现,转换成numpy以后都是一个二维的数组
        self.y[i]出现的是一个ndarray类型(nparray[2],字符串类型)
        self.y[i][0]才是提取出二维数组y中的具体的数
        """
        dist_list = [(np.linalg.norm(x_test-self.x[i]),self.y[i][0]) for i in range(len(self.x))]
        # print(f'我是:{dist_list}')
        # 对所有距离进行排序
        # 列表排序,默认是降序
        """
        实际为一个元组,key = lambda x:x[0] 0代表一维
        """
        dist_list.sort(key = lambda x: x[0])
        # print(f'我是:{dist_list}')
        # 取前k个最小距离对应的类别(y值)
        """
        -1代表取最后一列,当一个值时,得到一个一维numpy,即一维数组
        """
        y_list = [dist_list[i][-1] for i in range(self.k)]
        # print(y_list)
        # 对上述点的分类进行统计
        # 此处用到了一个Counter函数
        y_count = Counter(y_list).most_common()
        # print('11',y_count)
        return y_count[0][0]

# 创建一个机器人
doctor = knn_qingdaifu()
# 训练机器人
doctor.fit(x,y)

# 下面使用38位顾客的数据测试机器人诊断效果
# 读取38位顾客的气色,气味,脉象,体温等特征数据
test_x = pandas.read_csv('test_X.csv').values
# print(f'我是x:{test_x}')

# 诊断! 结果存放到result数组中
result = doctor.predict(test_x)
# print(f'我是result:{result}')

# 打印输出诊断结果,与实际的结果比较
# 读取38位顾客怀孕状态的实际值(0表示女娃,1表示男娃,2表示没有怀孕)
test_y = pandas.read_csv('test_y.csv')
# print(f'我是y_test:/n{test_y}')

labels=['女娃','男孩','没有怀孕']
i = 0
# 正确的诊断数
predictOKNum = 0
print("编号,诊断值,实际值,")
while i < test_y.shape[0]:
    # 第i个诊断结果与实际的第i个结果比较,相等表示诊断正确

    # if result[i] == (test_y.values[i,0]):
    if result[i] == (test_y.values[i,0]):
        predictOKNum = predictOKNum + 1
        okOrNo = '准确'
    else:
        okOrNo = '错误'
    print("%s,%s,%s,%s" %(i+1, labels[result[i]],labels[test_y.values[i,0]],okOrNo))
    i = i+1

print("诊断正确率:%s" % (predictOKNum/i))

在代码测试完以后,可以调用sklearn中自带的knn的API验证一下自己写的代码准确性,KNeighborsClassifier(n_neighbors=5);

代码中用到了一个求距离的高级函数,范式函数:np.linalg.norm();

上述代码为最基础的knn原理实现,在真实应用的API中,利用kd树来构造位置关系,减少计算量

注意:Counter是python内部自带的包,操作对象是list,不能操作array(numpy)

你可能感兴趣的:(机器学习,机器学习,人工智能,算法)