[机器学习常用算法]--(K近邻&决策树)

@[机器学习常用算法]–(K近邻&决策树)

K近邻算法

优点:
对异常值不敏感;
精度高;
缺点:
计算量大;

核心思想

  1. 计算当前点与已知类别的数据集中各点的距离;
  2. 距离按照递增方式排序;
  3. 选取与当前点距离最近的K个点;
  4. 确定k个点所在类别出现的频率;
  5. 出现频率最高的类别为当前点的预测类别;

距离计算(欧氏距离)

二维
在这里插入图片描述
三维
在这里插入图片描述
n维
在这里插入图片描述

python实现

参考:[https://blog.csdn.net/niuwei22007/article/details/49703719]


```python

```python
# coding=UTF8
from numpy import *
import operator


def createDataSet():
    """
    函数作用:构建一组训练数据(训练样本),共4个样本
    同时给出了这4个样本的标签,及labels
    """
    group = array([
        [1.0, 1.1],
        [1.0, 1.0],
        [0., 0.],
        [0., 0.1]
    ])
    labels = ['A', 'A', 'B', 'B']
    return group, labels


def classify0(inX, dataset, labels, k):
    """
    inX 是输入的测试样本,是一个[x, y]样式的
    dataset 是训练样本集
    labels 是训练样本标签
    k 是top k最相近的
    """
    # shape返回矩阵的[行数,列数],
    # 那么shape[0]获取数据集的行数,
    # 行数就是样本的数量
    dataSetSize = dataset.shape[0]

    """
    下面的求距离过程就是按照欧氏距离的公式计算的。
    即 根号(x^2+y^2)
    """

    diffMat = tile(inX, (dataSetSize, 1)) - dataset

    # diffMat就是输入样本与每个训练样本的差值,然后对其每个x和y的差值进行平方运算。
    # diffMat是一个矩阵,矩阵**2表示对矩阵中的每个元素进行**2操作,即平方。
    # sqDiffMat = [[1.0, 0.01],
    #              [1.0, 0.0 ],
    #              [0.0, 1.0 ],
    #              [0.0, 0.81]]
    sqDiffMat = diffMat ** 2

    # axis=1表示按照横轴,sum表示累加,即按照行进行累加。
    # sqDistance = [[1.01],
    #               [1.0 ],
    #               [1.0 ],
    #               [0.81]]
    sqDistance = sqDiffMat.sum(axis=1)

    # 对平方和进行开根号
    # distance = [1.3453624  1.27279221 0.14142136 0.1       ]
    distance = sqDistance ** 0.5

    # 按照升序进行快速排序,返回的是原数组的下标。
    # 比如,x = [30, 10, 20, 40]
    # 升序排序后应该是[10,20,30,40],他们的原下标是[1,2,0,3]
    # 那么,numpy.argsort(x) = [1, 2, 0, 3]

    # sortedDistIndicies = [3 2 1 0]
    sortedDistIndicies = distance.argsort()

    # 存放最终的分类结果及相应的结果投票数
    classCount = {}

    # 投票过程,就是统计前k个最近的样本所属类别包含的样本个数
    for i in range(k):
        # index = sortedDistIndicies[i]是第i个最相近的样本下标
        """
        列表distance中存放的为测试点与各个样本点之间的距离,sortedDistIndicies[i]为第i个离测试点最近的样本点
        """
        # voteIlabel = labels[index]是样本index对应的分类结果('A' or 'B')
        voteIlabel = labels[sortedDistIndicies[i]]
        # classCount.get(voteIlabel, 0)返回voteIlabel的值,如果不存在,则返回0
        # 然后将票数增1
        # classCount={'B': 2, 'A': 1}
        # items():将字典转化为元组
        # classCount.items()=dict_items([('B', 2), ('A', 1)])
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1

    # 把分类结果进行排序,然后返回得票数最多的分类结果
    # operator.itemgetter(1)按照元组中的第”1“项进行排序,从零开始。
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]


if __name__ == "__main__":
    # 导入数据
    dataset, labels = createDataSet()
    inX = [0.1, 0.1]
    # 简单分类
    className= classify0(inX, dataset, labels, 3)
    print('the class of test sample is %s' %className)

决策树

优点
计算量小
缺点
容易产生过度匹配(过拟合)
由于K近邻每次都需要计算与训练集中所有样本的距离,因此计算量大,另外,k近邻无法给出数据内的含义。
决策树就是k近邻的优化版。

几个要点

1.信息增益、熵;
2.剪枝(预剪枝、后剪枝):防止过拟合;

熵&信息增益

熵为信息的期望值,计算公式如下:
在这里插入图片描述
k:分类数目
p(i):选择该分类的概率

例:
在这里插入图片描述
信息熵
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
信息增益为:
类型:0.81-0.59=0.22
产地:0.81-0.34=0.47
票房:0.81-0.68=0.13

因此决策树应按照产地?类型?票房的顺序。

剪枝

参考:https://blog.csdn.net/u012328159/article/details/79285214
剪枝的作用:防止过拟合
对于剪枝的介绍上述文献很详细,看上面的文献即可。

对于剪枝的一点补充:
在实际的编程过程中可以设置两个参数(tols、tolN)
参数tols是容许的误差下降值。
参数tolN是切分的最小样本数。

例如:
对于tols:
划分之前的精度为90.1
划分之后的精度为90.2
if tols=0.2
则不会进行划分。
对于tolN:
如果当前当前节点有三个样本,但tolN=4,则该节点标记为叶节点,不再继续划分。

python实现


```python
import csv

from sklearn.feature_extraction import DictVectorizer
from sklearn import preprocessing
from sklearn import tree

film_data = open('film.csv','rt')
# reader = csv.reader(f) 此时reader返回的值是csv文件中每行的列表,将每行读取的值作为列表返回
# for row in reader:
#     print(row)
# 结果如下
# ['id', 'type', 'country', 'gross', 'watch']
# ['1', 'anime', 'Janan', 'low', 'yes']
# ['2', 'science', 'America', 'low', 'yes']
# ['3', 'anime', 'America', 'low', 'yes']
# ['4', 'action', 'America', 'high', 'yes']
# ['5', 'action', 'China', 'high', 'yes']
# ['6', 'anime', 'China', 'low', 'yes']
# ['7', 'science', 'France', '1ow', 'no']
# ['8', 'action', 'China', '1ow', 'no']
reader = csv.reader(film_data)

# 表头信息
herders = next(reader)
# print(herders)

features_list = []
result_list = []

for row in reader:
    # 读取结果,即'watch'
    result_list.append(row[-1])

    # 去掉首尾两列只保留type,country,gross
    # 创建字典
    # 键为herders[1:-1]  --》  type,country,gross
    # 值为row[1:-1]    --》    'anime', 'Janan', 'low'
    # 。。。

    # 对于zip     //将对象中对应的元素打包成一个个元组
    # 例如
    # a = [1, 2, 3] b = [4, 5, 6]   c = zip(a, b)
    # for item in c:
    #     print(item)
    #   输出
    #   (1, 4) (2, 5) (3, 6)

    # dict(zip(a, b))
    # {1: 4, 2: 5, 3: 6}
    # 将元组转化为字典
    features_list.append(dict(zip(herders[1:-1],row[1:-1])))
# print(result_list)
# print(features_list)

#将dict类型的list数据,转换成nuupy array
vec = DictVectorizer()
# dummyX样式如下
# [0. 0. 0. 1.| 0. 1. |0. 1. 0.]
# 因为有四个国家,'countny'对应四位
# 三种类型,'type'对应三位
# #注意,dummyx是按首字母排序的'countny','gross','type'
dummyX = vec.fit_transform(features_list).toarray()
# 对watch进行编码
# dummyY = [[1]  [1]  [1]  [1]  [1] [1] [0] [0]]
dummyY = preprocessing.LabelBinarizer().fit_transform(result_list)

# clf:DecisionTreeClassifier(class_weight=None, criterion='entropy', max_depth=None,
# #                        max_features=None, max_leaf_nodes=None,
# #                        min_impurity_decrease=0.0, min_impurity_split=None,
# #                        min_samples_leaf=1, min_samples_split=2,
# #                        min_weight_fraction_leaf=0.0, presort=False,
# #                        random_state=0, splitter='best')

clf = tree.DecisionTreeClassifier(criterion='entropy', random_state=0)
c1f = clf. fit(dummyX, dummyY)
# print("clf:"+str(clf))

# 利用pydotplus绘制决策树
import pydotplus
# 在安装GraphViz之后并手动添加了环境变量,但还是报错
# 运行下面的语句即可解决
import os
os.environ["PATH"] += os.pathsep + 'C:\software\\python_lib\\graphviz-2.38\\release\\bin'  #注意修改你的路径
# 将生成的数据进行可视化
dot_data = tree.export_graphviz(c1f,
                                feature_names=vec.get_feature_names(),
                                filled=True,
                                rounded=True,
                                special_characters=True,
                                out_file=None)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_pdf("film.pdf")

##开始预测
# A=([[0,0,0,1,0,1,0,1,0]])#日本(4)-低票房(2)-动画片(3)
B=([[0,0,1,0,0,1,0,1,0]])#法国(4)-低票房(2)-动画片(3)
#c=[1,0,0,0,1,0,1,0,0]J)#美国(4)-高票房(2)-动作片(3)
predict_result = clf.predict(B)
print("预测结果:"+str(predict_result))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值