聚类算法概述(k-Means++/FCM/凝聚层次聚类/DBSCAN)

K-means聚类算法的原理、应用与实例 阅读详情

欢迎光临我的博客:HaoyuHu’s Blog

参考自初识聚类算法:K均值、凝聚层次聚类和DBSCAN,模糊聚类FCM算法。

近期做完了labmu的tunet3.0,总算有时间学习一些东西了。目前想学的有聚类分析、图像识别算法和计算机网络方面的知识。在暑假实习期间,开始着手游戏编程。

聚类的目的

将数据划分为若干个簇,簇内相似性大,簇间相似性小,聚类效果好。用于从数据中提取信息和规律。

聚类的概念

  • 层次与划分:当允许存在子簇时,将数据按照层次划分,最终得到的是一颗树。树中包含的层次关系即为聚类划分的层次关系。各个子簇不重叠,每个元素都隶属于某个level的子簇中。
  • 互斥、重叠与模糊:这个概念的核心在于,所有集合元素都不完全隶属于任何一个簇,而是按照一定隶属度归属于所有簇。对于任意一个元素,其隶属度和一般为1。
  • 完全与部分:完全聚类要求所有数据元素都必须有隶属,而部分聚类则允许噪音存在,不隶属于任何簇。

簇的分类

  • 明显分离:不同簇间任意元素距离都大于簇内元素距离。从图像上观察是明显分离类型的簇。
  • 基于原型:任意元素与它所隶属的簇的簇中心(簇内元素集合的质心)的距离大于到其他簇中心的距离。
  • 基于图:图中节点为对象,弧权值为距离。类似于明显分离的定义或基于原型的定义,只是用弧权值代替了人为规定的距离。
  • 基于密度:基于密度的簇分类是较为常用,也是应用范围最为广泛的一种分类方法。元素的稠密程度决定了簇的分布。当存在并希望分辨噪声时,或簇形状不规则时,往往采用基于密度的簇分类。

常用的聚类分析算法

  • 基本k均值:即k-means算法。簇的分类是基于原型的。用于已知簇个数的情况,且要求簇的形状基本满足圆形,不能区分噪声。
  • 凝聚层次聚类:起初各个点为一个簇,而后按照距离最近凝聚,知道凝聚得到的簇个数满足用户要求。
  • DBscan:基于密度和划分的聚类方法。

聚类算法的基本思想

(1) 基本k均值聚类(hard c-means, HCM)

方法很简单,首先给出初始的几个簇中心。将所有元素按照到簇中心最近的归属原则,归属到各个簇。然后对各个簇求解新的簇中心(元素集合质心)。重复上述步骤直到质心不再明显变化后,即完成聚类。

采用何种距离可按照数据性质或项目要求。距离的分类可以参考A-star算法概述及其在游戏开发中的应用分析中提到的曼哈顿距离、对角线距离、欧几里得距离等。实际上相当于求解一个全局状态函数的最小值问题,状态函数是各个元素到最近簇中心的距离之和。

该算法的特点有如下几点:

  • 其一,不一定得到全局最优解,当初始簇中心不满足要求时,可能只能得到局部最优解,当然有学者通过一定的预处理使得得到的初始簇中心满足一定条件,从而能够得到全局最优解,并将方法名改为k-means++。
  • 其二,不能排除噪声点对聚类的影响。
  • 其三,要求簇形状接近圆形。
  • 要求完全聚类的情况。

k-Means++

python代码

此代码使用的是k-means++算法,采用约定的方法使得到的初始聚类中心能够在后面的迭代过程中收敛到最优解。

import math
import collections
import random
import copy
import pylab

try:
    import psyco
    psyco.full()
except ImportError:
    pass

FLOAT_MAX = 1e100

class Point:
    __slots__ = ["x", "y", "group"]
    def __init__(self, x = 0, y = 0, group = 0):
        self.x, self.y, self.group = x, y, group

def generatePoints(pointsNumber, radius):
    points = [Point() for _ in xrange(pointsNumber)]
    for point in points:
        r = random.random() * radius
        angle = random.random() * 2 * math.pi
        point.x = r * math.cos(angle)
        point.y = r * math.sin(angle)
    return points

def solveDistanceBetweenPoints(pointA, pointB):
    return (pointA.x - pointB.x) * (pointA.x - pointB.x) + (pointA.y - pointB.y) * (pointA.y - pointB.y)

def getNearestCenter(point, clusterCenterGroup):
    minIndex = point.group
    minDistance = FLOAT_MAX
    for index, center in enumerate(clusterCenterGroup):
        distance = solveDistanceBetweenPoints(point, center)
        if (distance < minDistance):
            minDistance = distance
            minIndex = index
    return (minIndex, minDistance)

def kMeansPlusPlus(points, clusterCenterGroup):
    clusterCenterGroup[0] = copy.copy(random.choice(points))
    distanceGroup = [0.0 for _ in xrange(len(points))]
    sum = 0.0
    for index in xrange(1, len(clusterCenterGroup)):
        for i, point in enumerate(points):
            distanceGroup[i] = getNearestCenter(point, clusterCenterGroup[:index])[1]
            sum += distanceGroup[i]
        sum *= random.random()
        for i, distance in enumerate(distanceGroup):
            sum -= distance;
            if sum < 0:
                clusterCenterGroup[index] = copy.copy(points[i])
                break
    for point in points:
        point.group = getNearestCenter(point, clusterCenterGroup)[0]
    return

def kMeans(points, clusterCenterNumber):
    clusterCenterGroup = [Point() for _ in xrange(clusterCenterNumber)]
    kMeansPlusPlus(points, clusterCenterGroup)
    clusterCenterTrace = [[clusterCenter] for clusterCenter in clusterCenterGroup]
    tolerableError, currentError = 5.0, FLOAT_MAX
    count = 0
    while currentError >= tolerableError:
        count += 1
        countCenterNumber = [0 for _ in xrange(clusterCenterNumber)]
        currentCenterGroup = [Point() for _ in xrange(clusterCenterNumber)]
        for point in points:
            currentCenterGroup[point.group].x += point.x
            currentCenterGroup[point.group].y += point.y
            countCenterNumber[point.group] += 1
        for index, center in enumerate(currentCenterGroup):
            center.x /= countCenterNumber[index]
            center.y /= countCenterNumber[index]
        currentError = 0.0
        for index, singleTrace in enumerate(clusterCenterTrace):
            singleTrace.append(currentCenterGroup[index])
            currentError += solveDistanceBetweenPoints(singleTrace[-1], singleTrace[-2])
            clusterCenterGroup[index] = copy.copy(currentCenterGroup[index])
        for point in points:
            point.group = getNearestCenter(point, clusterCenterGroup)[0]
    return clusterCenterGroup, clusterCenterTrace

def showClusterAnalysisResults(points, clusterCenterTrace):
    colorStore = ['or', 'og', 'ob', 'oc', 'om', 'oy', 'ok']
    pylab.figure(figsize=(9, 9), dpi = 80)
    for point in points:
        color = ''
        if point.group >= len(colorStore):
            color = colorStore[-1]
        else:
            color = colorStore[point.group]
        pylab.plot(point.x, point.y, color)
    for singleTrace in clusterCenterTrace:
        pylab.plot([center.x for center in singleTrace], [center.y for center in singleTrace], 'k')
    pylab.show()

def main():
    clusterCenterNumber = 5
    pointsNumber = 2000
    radius = 10
    points = generatePoints(pointsNumber, radius)
    _, clusterCenterTrace = kMeans(points, clusterCenterNumber)
    showClusterAnalysisResults(points, clusterCenterTrace)

main()

(1)Extra 基于模糊数学的c均值聚类(FCM)

模糊c均值聚类(fuzzy c-means clustering)与硬划分k均值聚类相同,都是一种基于划分的聚类分析方法,但FCM是HCM的自然进阶版。与k均值聚类不同的是,模糊c均值聚类的点按照不同的隶属度ui隶属于不同的聚类中心vi,聚类的过程类似k均值聚类。(详见:模糊聚类FCM算法)

聚类步骤:

  • 初始化。采用k-means++的方法确定初始聚类中心,确保最优解。
  • 确定各个点对各个聚类中心的隶属度u(i,j)。m为加权指数。公式如下:
  • u(i,j) = (sum(distance(point(j), center(i)) / distance(point(j), center(k)))^(1/(m-1)))^-1
  • 确定新的聚类中心,标记聚类中心变化轨迹。公式如下:
  • v(i) = sum(u(i,j)^m * point(j)) / sum(u(i,j)^m)
  • 判断聚类中心变化幅值是否小于给定的误差限。如不满足返回步骤2,否则退出循环。
  • 打印聚类中心轨迹和聚类结果。

FCM

python代码

import math
import collections
import random
import copy
import pylab

try:
    import psyco
    psyco.full()
except ImportError:
    pass

FLOAT_MAX = 1e100

class Point:
    __slots__ = ["x", "y", "group", "membership"]
    def __init__(self, clusterCenterNumber, x = 0, y = 0, group = 0):
        self.x, self.y, self.group = x, y, group
        self.membership = [0.0 for _ in xrange(clusterCenterNumber)]

def generatePoints(pointsNumber, radius, clusterCenterNumber):
    points = [Point(clusterCenterNumber) for _ in xrange(2 * pointsNumber)]
    count = 0
    for point in points:
        count += 1
        r = random.random() * radius
        angle = random.random() * 2 * math.pi
        point.x = r * math.cos(angle)
        point.y = r * math.sin(angle)
        if count == pointsNumber - 1:
            break
    for index in xrange(pointsNumber, 2 * pointsNumber):
        points[index].x = 2 * radius * random.random() - radius
        points[index].y = 2 * radius * random.random() - radius
    return points


def solveDistanceBetweenPoints(pointA, pointB):
    return (pointA.x - pointB.x) * (pointA.x - pointB.x) + (pointA.y - pointB.y) * (pointA.y - pointB.y)

def getNearestCenter(point, clusterCenterGroup):
    minIndex = point.group
    minDistance = FLOAT_MAX
    for index, center in enumerate(clusterCenterGroup):
        distance = solveDistanceBetweenPoints(point, center)
        if (distance < minDistance):
            minDistance = distance
            minIndex = index
    return (minIndex, minDistance)

def kMeansPlusPlus(points, clusterCenterGroup):
    clusterCenterGroup[0] = copy.copy(random.choice(points))
    distanceGroup = [0.0 for _ in xrange(len(points))]
    sum = 0.0
    for index in xrange(1, len(clusterCenterGroup)):
        for i, point in enumerate(points):
            distanceGroup[i] = getNearestCenter(point, clusterCenterGroup[:index])[1]
            sum += distanceGroup[i]
        sum *= random.random()
        for i, distance in enumerate(distanceGroup):
            sum -= distance;
            if sum < 0:
                clusterCenterGroup[index] = copy.copy(points[i])
                break
    return

def fuzzyCMeansClustering(points, clusterCenterNumber, weight):
    clusterCenterGroup = [Point(clusterCenterNumber) for _ in xrange(clusterCenterNumber)]
    kMeansPlusPlus(points, clusterCenterGroup)
    clusterCenterTrace = [[clusterCenter] for clusterCenter in clusterCenterGroup]
    tolerableError, currentError = 1.0, FLOAT_MAX
    while currentError >= tolerableError:
        for point in points:
            getSingleMembership(point, clusterCenterGroup, weight)
        currentCenterGroup = [Point(clusterCenterNumber) for _ in xrange(clusterCenterNumber)]
        for centerIndex, center in enumerate(currentCenterGroup):
            upperSumX, upperSumY, lowerSum = 0.0, 0.0, 0.0
            for point in points:
                membershipWeight = pow(point.membership[centerIndex], weight)
                upperSumX += point.x * membershipWeight
                upperSumY += point.y * membershipWeight
                lowerSum += membershipWeight
            center.x = upperSumX / lowerSum
            center.y = upperSumY / lowerSum
        # update cluster center trace
        currentError = 0.0
        for index, singleTrace in enumerate(clusterCenterTrace):
            singleTrace.append(currentCenterGroup[index])
            currentError += solveDistanceBetweenPoints(singleTrace[-1], singleTrace[-2])
            clusterCenterGroup[index] = copy.copy(currentCenterGroup[index])
    for point in points:
        maxIndex, maxMembership = 0, 0.0
        for index, singleMembership in enumerate(point.membership):
            if singleMembership > maxMembership:
                maxMembership = singleMembership
                maxIndex = index
        point.group = maxIndex
    return clusterCenterGroup, clusterCenterTrace

def getSingleMembership(point, clusterCenterGroup, weight):
    distanceFromPoint2ClusterCenterGroup = [solveDistanceBetweenPoints(point, clusterCenterGroup[index]) for index in xrange(len(clusterCenterGroup))]
    for centerIndex, singleMembership in enumerate(point.membership):
        sum = 0.0
        isCoincide = [False, 0]
        for index, distance in enumerate(distanceFromPoint2ClusterCenterGroup):
            if distance == 0:
                isCoincide[0] = True
                isCoincide[1] = index
                break
            sum += pow(float(distanceFromPoint2ClusterCenterGroup[centerIndex] / distance), 1.0 / (weight - 1.0))
        if isCoincide[0]:
            if isCoincide[1] == centerIndex:
                point.membership[centerIndex] = 1.0
            else:
                point.membership[centerIndex] = 0.0
        else:
            point.membership[centerIndex] = 1.0 / sum

def showClusterAnalysisResults(points, clusterCenterTrace):
    colorStore = ['or', 'og', 'ob', 'oc', 'om', 'oy', 'ok']
    pylab.figure(figsize=(9, 9), dpi = 80)
    for point in points:
        color = ''
        if point.group >= len(colorStore):
            color = colorStore[-1]
        else:
            color = colorStore[point.group]
        pylab.plot(point.x, point.y, color)
    for singleTrace in clusterCenterTrace:
        pylab.plot([center.x for center in singleTrace], [center.y for center in singleTrace], 'k')
    pylab.show()

def main():
    clusterCenterNumber = 5
    pointsNumber = 2000
    radius = 10
    weight = 2
    points = generatePoints(pointsNumber, radius, clusterCenterNumber)
    _, clusterCenterTrace = fuzzyCMeansClustering(points, clusterCenterNumber, weight)
    showClusterAnalysisResults(points, clusterCenterTrace)

main()

该算法的特点有如下几点:

  • 主要特点与普通的k均值聚类类似。
  • 要求完全聚类,不能区分噪声点。
  • 聚类的中心符合度更高,但计算效率相对较低。
  • 采用了平滑参数和隶属度的概念,使得各点的并不直接隶属于单个聚类中心。

(2) 凝聚层次聚类

初始状态各个元素各自为簇,每次合并簇间距离最小的簇。直到簇个数满足要求或合并超过90%。类似huffman树算法和查并集。上述距离的定义也有几种分类:包括簇间元素的最小距离,簇间元素的最大距离,和簇质心距离。

该算法的特点有如下几点:

  • 凝聚聚类耗费的存储空间相对于其他几种方法要高。
  • 可排除噪声点的干扰,但有可能噪声点分为一簇。
  • 适合形状不规则,不要求聚类完全的情况。
  • 合并操作不能撤销。
  • 应注意,合并操作必须有一个合并限制比例,否则可能发生过度合并导致所有分类中心聚集,造成聚类失败。

凝聚层次聚类

python代码

import math
import collections
import random
import copy
import pylab

try:
    import psyco
    psyco.full()
except ImportError:
    pass

FLOAT_MAX = 1e100

class Point:
    __slots__ = ["x", "y", "group"]
    def __init__(self, x = 0, y = 0, group = 0):
        self.x, self.y, self.group = x, y, group

def generatePoints(pointsNumber, radius):
    points = [Point() for _ in xrange(4 * pointsNumber)]
    originX = [-radius, -radius, radius, radius]
    originY = [-radius, radius, -radius, radius]
    count = 0
    countCenter = 0
    for index, point in enumerate(points):
        count += 1
        r = random.random() * radius
        angle = random.random() * 2 * math.pi
        point.x = r * math.cos(angle) + originX[countCenter]
        point.y = r * math.sin(angle) + originY[countCenter]
        point.group = index
        if count >= pointsNumber * (countCenter + 1):
            countCenter += 1    
    return points

def solveDistanceBetweenPoints(pointA, pointB):
    return (pointA.x - pointB.x) * (pointA.x - pointB.x) + (pointA.y - pointB.y) * (pointA.y - pointB.y)

def getDistanceMap(points):
    distanceMap = {}
    for i in xrange(len(points)):
        for j in xrange(i + 1, len(points)):
            distanceMap[str(i) + '#' + str(j)] = solveDistanceBetweenPoints(points[i], points[j])
    distanceMap = sorted(distanceMap.iteritems(), key=lambda dist:dist[1], reverse=False)
    return distanceMap

def agglomerativeHierarchicalClustering(points, distanceMap, mergeRatio, clusterCenterNumber):
    unsortedGroup = {index: 1 for index in xrange(len(points))}
    for key, _ in distanceMap:
        lowIndex, highIndex = int(key.split('#')[0]), int(key.split('#')[1])
        if points[lowIndex].group != points[highIndex].group:
            lowGroupIndex = points[lowIndex].group
            highGroupIndex = points[highIndex].group
            unsortedGroup[lowGroupIndex] += unsortedGroup[highGroupIndex]
            del unsortedGroup[highGroupIndex]
            for point in points:
                if point.group == highGroupIndex:
                    point.group = lowGroupIndex
        if len(unsortedGroup) <= int(len(points) * mergeRatio):
            break
    sortedGroup = sorted(unsortedGroup.iteritems(), key=lambda group: group[1], reverse=True)
    topClusterCenterCount = 0
    print sortedGroup, len(sortedGroup)
    for key, _ in sortedGroup:
        topClusterCenterCount += 1
        for point in points:
            if point.group == key:
                point.group = -1 * topClusterCenterCount
        if topClusterCenterCount >= clusterCenterNumber:
            break
    return points


def showClusterAnalysisResults(points):
    colorStore = ['or', 'og', 'ob', 'oc', 'om', 'oy', 'ok']
    pylab.figure(figsize=(9, 9), dpi = 80)
    for point in points:
        color = ''
        if point.group < 0:
            color = colorStore[-1 * point.group - 1]
        else:
            color = colorStore[-1]
        pylab.plot(point.x, point.y, color)
    pylab.show()

def main():
    clusterCenterNumber = 4
    pointsNumber = 500
    radius = 10
    mergeRatio = 0.025
    points = generatePoints(pointsNumber, radius)
    distanceMap = getDistanceMap(points)
    points = agglomerativeHierarchicalClustering(points, distanceMap, mergeRatio, clusterCenterNumber)
    showClusterAnalysisResults(points)

main()

(3) DBscan

DBscan是一种基于密度的聚类算法。因此首先应定义密度的概念。密度是以一个点为中心2*EPs边长的正方形区域内点的个数。并将不同密度的点划归为不同类型的点:

  • 当密度大于阈值MinPs时,称为核心点。
  • 当密度小于阈值MinPs,但领域内核心点的数量大于等于1,称为边界点。
  • 非核心点且非边界点,称为噪声点。

具体操作:

  • 将所有邻近的核心点划分到同一个簇中。
  • 将所有边界点划分到其领域内的核心点的簇中。
  • 噪声点不做归属处理。

该算法的特点有如下几点:

  • 可排除噪声点的干扰。
  • 适合形状不规则,不要求聚类完全的情况。
  • 合并操作不能撤销。
  • minPointsNumberWithinBoundary和Eps决定了聚类的粒度和范围,当Eps增大或minPointsNumberWithinBoundary减小时,都会使聚类的粒度更粗,形成范围更大的簇。对于特定的问题,需要调整Eps和minPointsNumberWithinBoundary以满足聚类的要求。
  • 基于密度的聚类一定程度上回避了距离的计算,可以提高效率。

dbscan

python代码

import math
import collections
import random
import copy
import pylab

try:
    import psyco
    psyco.full()
except ImportError:
    pass

FLOAT_MAX = 1e100

CORE_POINT_TYPE = -2
BOUNDARY_POINT_TYPE = 1 #ALL NONE-NEGATIVE INTEGERS CAN BE BOUNDARY POINT TYPE
OTHER_POINT_TYPE = -1

class Point:
    __slots__ = ["x", "y", "group", "pointType"]
    def __init__(self, x = 0, y = 0, group = 0, pointType = -1):
        self.x, self.y, self.group, self.pointType = x, y, group, pointType

def generatePoints(pointsNumber, radius):
    points = [Point() for _ in xrange(4 * pointsNumber)]
    originX = [-radius, -radius, radius, radius]
    originY = [-radius, radius, -radius, radius]
    count = 0
    countCenter = 0
    for index, point in enumerate(points):
        count += 1
        r = random.random() * radius
        angle = random.random() * 2 * math.pi
        point.x = r * math.cos(angle) + originX[countCenter]
        point.y = r * math.sin(angle) + originY[countCenter]
        point.group = index
        if count >= pointsNumber * (countCenter + 1):
            countCenter += 1    
    return points

def solveDistanceBetweenPoints(pointA, pointB):
    return (pointA.x - pointB.x) * (pointA.x - pointB.x) + (pointA.y - pointB.y) * (pointA.y - pointB.y)

def isInPointBoundary(centerPoint, customPoint, halfScale):
    return customPoint.x <= centerPoint.x + halfScale and customPoint.x >= centerPoint.x - halfScale and customPoint.y <= centerPoint.y + halfScale and customPoint.y >= centerPoint.y - halfScale

def getPointsNumberWithinBoundary(points, halfScale):
    pointsIndexGroupWithinBoundary = [[] for _ in xrange(len(points))]
    for centerIndex, centerPoint in enumerate(points):
        for index, customPoint in enumerate(points):
            if centerIndex != index and isInPointBoundary(centerPoint, customPoint, halfScale):
                pointsIndexGroupWithinBoundary[centerIndex].append(index)
    return pointsIndexGroupWithinBoundary

def decidePointsType(points, pointsIndexGroupWithinBoundary, minPointsNumber):
    for index, customPointsGroup in enumerate(pointsIndexGroupWithinBoundary):
        if len(customPointsGroup) >= minPointsNumber:
            points[index].pointType = CORE_POINT_TYPE
    for index, customPointsGroup in enumerate(pointsIndexGroupWithinBoundary):
        if len(customPointsGroup) < minPointsNumber:
            for customPointIndex in customPointsGroup:
                if points[customPointIndex].pointType == CORE_POINT_TYPE:
                    points[index].pointType = customPointIndex

def mergeGroup(points, fromIndex, toIndex):
    for point in points:
        if point.group == fromIndex:
            point.group = toIndex

def dbscan(points, pointsIndexGroupWithinBoundary, clusterCenterNumber):
    countGroupsNumber = {index: 1 for index in xrange(len(points))}
    for index, point in enumerate(points):
        if point.pointType == CORE_POINT_TYPE:
            for customPointIndex in pointsIndexGroupWithinBoundary[index]:
                if points[customPointIndex].pointType == CORE_POINT_TYPE and points[customPointIndex].group != point.group:
                    countGroupsNumber[point.group] += countGroupsNumber[points[customPointIndex].group]
                    del countGroupsNumber[points[customPointIndex].group]
                    mergeGroup(points, points[customPointIndex].group, point.group)
        #point.pointType >= 0 means it is BOUNDARY_POINT_TYPE
        elif point.pointType >= 0:
            corePointGroupIndex = points[point.pointType].group
            countGroupsNumber[corePointGroupIndex] += countGroupsNumber[point.group]
            del countGroupsNumber[point.group]
            point.group = corePointGroupIndex
    countGroupsNumber = sorted(countGroupsNumber.iteritems(), key=lambda group: group[1], reverse=True)
    count = 0
    for key, _ in countGroupsNumber:
        count += 1
        for point in points:
            if point.group == key:
                point.group = -1 * count
        if count >= clusterCenterNumber:
            break

def showClusterAnalysisResults(points):
    colorStore = ['or', 'og', 'ob', 'oc', 'om', 'oy', 'ok']
    pylab.figure(figsize=(9, 9), dpi = 80)
    for point in points:
        color = ''
        if point.group < 0:
            color = colorStore[-1 * point.group - 1]
        else:
            color = colorStore[-1]
        pylab.plot(point.x, point.y, color)
    pylab.show()

def main():
    clusterCenterNumber = 4
    pointsNumber = 500
    radius = 10
    Eps = 2
    minPointsNumber = 18
    points = generatePoints(pointsNumber, radius)
    pointsIndexGroupWithinBoundary = getPointsNumberWithinBoundary(points, Eps)
    decidePointsType(points, pointsIndexGroupWithinBoundary, minPointsNumber)
    dbscan(points, pointsIndexGroupWithinBoundary, clusterCenterNumber)
    showClusterAnalysisResults(points)

main()

后记

在学习和分析过程中发现几点待解决的问题:

  • 其一,上述聚类过程都需要人为指定聚类中心数目,然而聚类的过程如果需人为干预,这可能是一个比较麻烦的问题。解决办法可以是采用多个候选聚类中心数目{i,i+1,...k},对于不同的聚类中心数目都会有对应的分析结果,再采用贝叶斯定理。另一方面,机器无法知道人所需要的聚类粒度和聚类数目,如果完全由机器确定,也是不合理的。
  • 其二,k-means聚类必须是完全聚类,对距离的选择也可以依据问题而定。
  • 其三,实际上凝聚层次聚类和基于密度的dbscan聚类都有一个合并的过程,对于这种合并最好的算法应该是查并集,其时间复杂度为O(n * f(n)),对于目前常见的大整数n,f(n) < 4。但如果过于追求效率,那么就违背了python语言开发和分析数据的优势。
  • 其四,凝聚层次聚类和基于密度的dbscan聚类都对合并的程度有一定要求。凝聚层次聚类通过mergeRatio来确定合并的比例;而dbscan是通过Eps和minPointsNumber来确定聚类的粒度。
聚类算法原理与实战:K-Means++、DBSCAN选型指南 聚类是无监督学习的核心技术,用于在无标签数据中发现内在结构与自然分组。其本质是基于相似性度量(如欧氏距离、密度连通性)对样本进行分组,从而揭示数据分布的隐含模式。技术价值在于降低认知复杂度、支撑用户分群、异常检测与探索性分析。典型应用场景包括电商用户行为分群、地理热力图生成、基因序列分析及文本语义聚类。K-Means++通过概率化初始化提升稳定性,DBSCAN则以密度驱动机制天然适应不规则形状与噪声识别——二者并非迭代升级关系,而是面向不同数据形态(球形假设 vs 密度异质性)的互补工具。本文聚焦算法原理差 阅读详情

相关推荐

机器学习算法——聚类任务

1、K-Means 2、K-medoids 3、K-medians 4、层次聚类 5、DBSCAN 6、OPTICS 7、谱聚类 Spectral Clustering 8、高斯混合模型GMM 9、模糊C-means FCM 10、Mean Shift 11、BIRCH 12、Affinity Propagation 13、对比总结 14、完整代码

cjnn0710的博客 1086

【机器学习】(十九)聚类:k均值聚类、凝聚聚类、DBSCAN,算法评估

聚类:将数据划分成组的任务。这些组叫簇。 k均值聚类(KMeans) 迭代算法:将每个数据点分配给最近的簇中心->簇中心修改为所分配点的平均值->循环前两步,直至簇中心不再变化。 import matplotlib.pyplot as plt from sklearn.datasets import make_moons from sklearn.cluster import KMeans # two_moons数据集 x, y = make_moons(n_samples=200, noi

一亿少女的梦 1464

FCM+聚类+算法

FCM+聚类+算法 C-means,常称作K-means算法,是基于距离的聚类算法。采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为类簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。其基本思想:取定c 类,选取c 个初始聚类中心即 , 即代表点 。按最小距离原则将各样本分配到离代表点最近的一类中 ,不断重新计算类中心 ,调整各样本类别,最终使聚类准则函数 Je 最小。算法采用误差平方和准则函数作为聚类准则函数。 K-Means简单易于实现.

data+scenario+science+insight 515

常见的六大聚类算法

(1)首先确定半径r和minPoints. 从一个没有被访问过的任意数据点开始,以这个点为中心,r为半径的圆内包含的点的数量是否大于或等于minPoints,如果大于或等于minPoints则改点被标记为central point,反之则会被标记为noise point。(2)每一次滑动到新的区域,计算滑动窗口内的均值来作为中心点,滑动窗口内的点的数量为窗口内的密度。(3)基于这些概率我们计算高斯分布参数使得数据点的概率最大化,可以使用数据点概率的加权来计算这些新的参数,权重就是数据点属于该簇的概率。

m0_57656758的博客 4922

电网加密芯片全解析:分类与功能​

在电网数字化转型的浪潮中,数据安全和设备的身份认证变得愈发重要。加密芯片作为保障电网信息安全的核心部件,凭借独特的技术特性,在不同应用场景下发挥着关键作用,有力推动着智能电网的安全稳定发展。接下来,我们将对电网中常见的加密芯片展开分类介绍,并探讨其对应的功能。​。

1962

DCDC系列(一): COT DCDC基本原理

电流环DCDC属于双环控制模式,根据电流检测的位置,分为峰值电流环控制模式、谷值电流环控制模式和平均电流环控制模式,主要由输出电压反馈环和电流环两个环路来实现控制,其瞬态响应比电压环更好,且有自动限流的功能,但仍需要斜坡补偿网络,且对噪声敏感。Stage3: 在下管NMOS打开阶段,由于后级负载此时间段内消耗的电量较少,所以VFB还未低至Vref,所以此阶段中,上管PMOS和下管NMOS均处于关断状态,此时的电感电流为0mA,此阶段测的VSW上的电压就是Cout上的电压VREG;

weixin_40073649的博客 3938

一文盘点5种聚类算法,数据科学家必备!

来源:中国统计网本文约4100字,建议阅读10+分钟。本文为你分析基本聚类方法的实现概念,并给出每种算法的优缺点及实际的应用场景。聚类是一种将数据点按一定规则分群的机器学...

THU数据派 1208

Cesium生态盘点:超图、火星3D等15个二次开发框架对比

本文深入解析Cesium生态中的15个二次开发框架,包括超图、火星3D等主流选择,帮助开发者根据项目需求进行精准选型。从性能表现、功能完备性、开发友好度等维度进行对比,特别适合需要处理地理空间数据和构建三维可视化的JavaScript开发者。

weixin_28197941的博客 497

两种聚类方法——K均值聚类(K-means)算法和模糊C均值聚类(FCM)算法的简述与在MATLAB中的实现

目录1.K-means算法1.1算法流程1.2程序实现实验结果原始数据集聚类结果2.FCM算法2.1算法流程功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 在科学计算领域,聚类算法一般都是作为其他算法分析的基础,对数据进行聚类可以

qq_44397802的博客 1万+

用Stata复现经典文献:上市公司全要素生产率(TFP)计算全流程(含LP/OP代码解读)

本文提供了使用Stata软件复现上市公司全要素生产率(TFP)计算的完整实战指南。重点解读了主流的Levinsohn-Petrin(LP)和Olley-Pakes(OP)半参数估计方法,通过详细的数据清洗、变量构建与价格平减步骤,手把手演示了如何准确测算TFP,并强调了LP方法在处理中国上市公司数据时的稳定性和适用性。

b0c1d2的博客 592

Android15 修改触摸点上限为40

把MAX_POINTER_ID从默认的31修改为39,这里为什么要从31修改为39,是因为上面说明用BitSet32极限就只能支持32个点,因为从最小的ID是0,所以要支持40个点ID也要对应改为39.最近有个需求,需要修改Android系统的触摸点数,Android系统默认的点数是16个点,因为现在是大屏项目,有客户需要修改为40个点,好吧,客户最大。6.最后进行编译,开机开启触摸点检测,可以使用开发者模式中的显示触摸点功能,再叫上3个人,用双掌触摸屏幕,发现左上角有显示40个触摸点,修改成功。

tzj1058756809的博客 573

数据挖掘——常用聚类算法总结

概述 数据挖掘常又被称为价值发现或者是数据勘探,一般是指从大量的、不完全的、有噪声的、模糊的、随机的实际应用数据中,提取隐含在其中的,人们事先不知道的、但又是潜在有用的信息和知识的过程。它是一种大量数据的高级处理方式。 常用的数据挖掘算法分为四大类:聚类、分类、关联以及推荐算法。另外还有一个预处理:降维算法 聚类算法 聚类是在一群未知类别标号的样本上,用某种算法将他们分成若干类别,这是一种无监督学...

神技圈子的博客 1万+

华为OD新系统机试真题 2026.5.10 - 美观的灯笼

华为OD新系统机试真题【美观的灯笼】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【美观的灯笼】

qq_45776114的博客 640

-means聚类、GMM高斯聚类、canopy聚类、DBSCAN聚类、FCM聚类、ISODATA聚类、k-medoid聚类、层次聚类、谱聚类 对比

DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的聚类算法,其原理是通过识别数据空间中的“拥挤”区域,即许多数据点靠近在一起的区域,来形成聚类。在DBSCAN中,如果一个点的邻域内包含足够多的点(根据给定的密度阈值),则该点被视为核心点,而密集区域是由核心点及其邻域内的点构成的。同时,GMM的聚类结果具有软聚类的特性,即数据点可以属于多个聚类中心,这可以更好地反映数据的真实情况。

2401_83250053的博客 1462

基于STM32开发板的USB MIDI键盘实现

在本文中,我们介绍了如何使用STM32开发板和相应的软件工具来实现USB MIDI键盘。通过配置STM32CubeMX和编写相应的源代码,我们能够将STM32开发板转换为一个功能齐全的USB MIDI设备。我们将使用STM32开发板和相应的软件工具来实现这一功能,并提供相应的源代码供参考。此时,您应该可以使用STM32开发板作为USB MIDI键盘,并在按键按下时听到相应的音符。在STM32CubeMX中,选择适当的STM32型号,并启动一个新的项目。然后,将生成的可执行文件烧录到STM32开发板中。

2301_79326616的博客 1588

【异常】Python环境中没有安装 `openpyxl` 模块提示ModuleNotFoundError: No module named ‘openpyxl‘

是一个用于读写Excel 2010 xlsx/xlsm/xltx/xltm文件的库。只是示例版本号,你可以根据需要选择不同的版本。安装完成后,再次尝试运行你的程序,应该就不会再出现。,这表明你的Python环境中缺少。运行一个Python程序时遇到了。如果由于某些原因你无法直接使用。,你可以指定版本号来安装,这里。要解决这个问题,你需要安装。

奶爸的编程之路,也就一周冷个三天 3396

基于聚类的图像分割——Python实现

文章目录0 图像读取1 算法实现1.1 K-Means1.2 FCM聚类1.3 漂移均值1.4 谱聚类1.5 Affinity Propagation聚类1.6 Birch聚类1.7 DBSCAN聚类1.8 高斯混合模型1.9 OPTICS聚类1.10 Agglomerative聚类2 作者注 0 图像读取 import numpy as np from PIL import Image as image def loadData(filePath): f = open(filePath,'rb')

qq_41905413的博客 1万+

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

【机器学习】--7.K-means算法(聚类)

聚类分析是在没有给定划分类别的情况下,根据数据相似度进行样本分组的一种方法。与分类模型需要使用有类标记样本构成的训练数据不同,聚类模型可以建立在无类标记的数据上,是一种非监督的学习算法。聚类的输入是一组未被标记的样本,聚类根据数据自身的距离或相似度将它们划分为若干个簇,划分的原则就是使簇内样本相似性最大,簇与簇之间的相似性最小。

我是个好人呀,O(∩_∩)O 3093

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

聚类算法(k_means)

1 聚类分析 聚类: 通过一定的算法将原始数据划分成多个数据簇 没有预先定义好的类别 同一簇内部数据样本之间有很大的相似性,不同簇内部的数据相似性很小 相似度与距离度量: 定义距离来度量表示相似度:欧式距离,曼哈顿距离(Dij=∣xi−xj∣+∣yi−yj∣D_{ij}=|x_i-x_j|+|y_i-y_j|Dij​=∣xi​−xj​∣+∣yi​−yj​∣),闵可夫斯基距离(n次欧式距离),切...

m0_38018799的博客 2525

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

机器学习之聚类(Clustering,包含k-means,DBSCAN等算法)

聚类(Clustering) 文章目录聚类(Clustering)基本内容1. 关于主要思想(聚类任务)2. 关于聚类规则(聚类算法)2.1 划分方法(partitioning method)2.1.1 k-means 算法算法步骤编程实现结果心得优缺点2.1.2 高斯混合聚类2.2 层次方法(hierarchical method)2.3 基于密度(density-based method)2.3.1 具有噪声应用的基于密度的空间聚类(Density-Based Spatial Clustering of

deepsprings的博客 862

各种聚类算法的介绍和比较

一、简要介绍1、聚类概念聚类就是按照某个特定标准(如距离准则)把一个数据集分割成不同的类或簇,使得同一个簇内的数据对象的相似性尽可能大,同时不在同一个簇中的数据对象的差异性也尽可能地大。即聚类后同一类的数据尽可能聚集到一起,不同数据尽量分离。 2、聚类和分类的区别聚类技术通常又被称为无监督学习,因为与监督学习不同,在聚类中那些表示数据类别的分类或者分组信息是没有的。 Clustering (聚类),

abc200941410128的博客 13万+

如何使用MATLAB代码编写,七种常见聚类算法等。

如何使用MATLAB代码编写,七种常见聚类算法等。 代码含详细注释,数据存入Excel,替换原有的“数据集”即可。

2501_90824910的博客 1270

机器学习中的聚类理论与K-means算法详解

本文系统阐述了聚类分析的理论框架与算法体系,重点剖析了K-means算法的原理、实现及优化策略。文章首先介绍了聚类的基本概念、应用场景和评估指标;其次对各类聚类算法进行比较分析;然后详细解析K-means算法的核心思想、数学原理及优缺点;并提供了Python实现示例及优化技巧。文章还探讨了2025年K-means算法的最新研究进展,包括改进算法、理论创新和电商应用案例。最后指出当前面临的挑战(如初始值敏感、K值确定)和未来发展方向(如自适应K值选择、深度聚类)。研究表明,K-means算法通过持续优化仍保持

小李独爱秋的博客 1866

fcm模糊聚类matlab实例_聚类与K-Means

作者:王浩本文介绍无监督学习中最基础的一种K-Means,全文共2300字,简单易懂,估计阅读时间8分钟。在传统的数据挖掘领域中,聚类是其中最常见的方法。其种类层出不穷,有基于层次,密度,网格以及原型的聚类方法,还有核聚类,谱聚类等等。在同一聚类方法中也会针对数据集或者是算法本身的缺点引申出各种各样的升级的算法版本,所以聚类方法保罗万象,我们只能管中窥豹,逐个探索,最后由点串面,达到对聚类的总体...

weixin_39833469的博客 282

软聚类算法:模糊聚类 (Fuzzy Clustering)

我们之前听说的大部分聚类算法均为硬聚类,即要求每个数据点只能属于一个特定的簇。不同于硬聚类,软聚类放松了限制,即允许数据点可以同时属于多个簇。本文所要介绍的模糊聚类即为一种常见的软聚类算法。

lucius-liu.cn 6410
上一篇: Leetcode220-Contains Duplicate III
下一篇: OpenCV实现图像搜索引擎(Image Search Engine)
coderhuhy
博客等级 码龄12年 24粉丝 40原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值