k-means,KNN,二分斐波那契查找

k-means类聚算法

概念,是干啥的

将一些点按距离(可以按需定义距离,比如欧几里得距离)分为k个聚落。最后使得误差平方和局部最小。

k-means算法思想

先随机选取K个对象作为初始的聚类中心。然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。一旦全部对象都被分配了,每个聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是以下任何一个:
1)没有(或最小数目)对象被重新分配给不同的聚类。
2)没有(或最小数目)聚类中心再发生变化。
3)误差平方和局部最小。
(from百度百科)
这个算法貌似并没有用到top-k的求法。而且算法可以自己慢慢调整质心从而完成分类,训练过程简单粗暴。

代码

import numpy as np
import pandas as pd
import random
import sys
import time
class KMeansClusterer:
    def __init__(self,ndarray,cluster_num):
        self.ndarray = ndarray
        self.cluster_num = cluster_num
        self.points=self.__pick_start_point(ndarray,cluster_num)
         
    def cluster(self):
        result = []
        for i in range(self.cluster_num):
            result.append([])
        for item in self.ndarray:
            distance_min = sys.maxsize
            index=-1
            for i in range(len(self.points)):                
                distance = self.__distance(item,self.points[i])
                if distance < distance_min:
                    distance_min = distance
                    index = i
            result[index] = result[index] + [item.tolist()]
        new_center=[]
        for item in result:
            new_center.append(self.__center(item).tolist())
        # 中心点未改变,说明达到稳态,结束递归
        if (self.points==new_center).all():
            return result
         
        self.points=np.array(new_center)
        return self.cluster()
             
    def __center(self,list):
        #计算一组坐标的中心点
        # 计算每一列的平均值
        return np.array(list).mean(axis=0)
    def __distance(self,p1,p2):
        #计算两点间距
        
        tmp=0
        for i in range(len(p1)):
            tmp += pow(p1[i]-p2[i],2)
        return pow(tmp,0.5)
    def __pick_start_point(self,ndarray,cluster_num):
        
        if cluster_num <0 or cluster_num > ndarray.shape[0]:
            raise Exception("簇数设置有误")
      
        # 随机点的下标
        indexes=random.sample(np.arange(0,ndarray.shape[0],step=1).tolist(),cluster_num)
        points=[]
        for index in indexes:
            points.append(ndarray[index].tolist())
        return np.array(points)

KNN算法

KNN算法是干啥的

现在有一堆点(n维特征向量),他们分属不同的类。新来一个点,要判断这个点属于哪类就可以用KNN算法预测。

KNN算法原理

KNN的全称是K Nearest Neighbors,意思是K个最近的邻居。K个最近邻居,毫无疑问,K的取值肯定是至关重要的。KNN的原理就是当预测一个新的值x的时候,根据它距离最近的K个点是什么类别来判断x属于哪个类别。最近的k个点里那个种类最多那x就是哪一类。同样这个距离可以自己定义。
KNN算法和k-means算法挺像的,但是本质不一样。

top-k的求法

这个可以每次新来一个点都把原来的点跑一边求出所有距离,然后就是传统的top-k问题了,可以bfptr之类的算法O(n)搞定,也可以优先队列O(nlogk)。。。
但是上述算法太亏了,每次新来点并没有利用上以前已经知道的信息。标准的做法是KD-tree实现。KD-tree才是KNN算法的核心!

KD-tree

KDTree(K-dimension Tree)是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。KDTree是一种二叉树,表示对k维空间的一种划分构造KDTree相当于不断地利用垂直于坐标轴的超平面将k维空间进行切分,构成一系列的k维超矩形区域。KDTree的每个节点对应于一个k维超矩形区域。利用KDTree可以省去对大部分数据点的搜索,从而减少搜索的计算量。如图。
在这里插入图片描述
树上每下降一层,就是对父节点代表空间的一次划分,根据树节点记录的信息就能比较新节点离哪边空间近,就往那边走。但有时会出现两边都有可能的情况,这时就都dfs一次。查找期望复杂度是logn的,但是证明好像非常复杂。

k值的选择

k值的选择直接影响了结果合不合理。训练k值的方法很简单,暴力枚举k,算一下类的方差,找到最优的k就行。但是每组样本都这样搞太浪费了,一般来说最好的k都不会超过20。

二分与斐波那契查找比较

斐波那契查找是啥

在黄金分割点,分开查找序列为左右部分,选一部分往下走。

斐波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的。他要求开始表中记录的个数为某个斐波那契数小1,n=F(k)-1;
开始将k值与第F(k-1)位置的记录进行比较(及mid=low+F(k-1)-1),比较结果也分为三种
1)相等,mid位置的元素即为所求
2)>,low=mid+1,k-=2;
3)<,high=mid-1,k-=1。
说明:两部分长度都是斐波那契数-1,相当于斐波那契数列往前一位或2位,所以可以递归的应用斐波那契查找。

比较

两者理论最坏和平均复杂度都是O(logn)。很明显,斐波那契查找最坏情况比二分的比较次数多一些(每次都走长的部分),但是他不牵涉除法运算。。。这个貌似除以2直接移位就能破。所以一般还是二分查找方便,还不用预处理斐波那契数列。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值