検索
ホームページバックエンド開発Python チュートリアルPython で実装された Kmeans++ アルゴリズムの例

1、从Kmeans说起

Kmeans是一个非常基础的聚类算法,使用了迭代的思想,关于其原理这里不说了。下面说一下如何在matlab中使用kmeans算法。

创建7个二维的数据点:

复制代码 代码如下:
x=[randn(3,2)*.4;randn(4,2)*.5+ones(4,1)*[4 4]];
使用kmeans函数:
复制代码 代码如下:
class = kmeans(x, 2);
x是数据点,x的每一行代表一个数据;2指定要有2个中心点,也就是聚类结果要有2个簇。 class将是一个具有70个元素的列向量,这些元素依次对应70个数据点,元素值代表着其对应的数据点所处的分类号。某次运行后,class的值是:
复制代码 代码如下:

 2
 2
 2
 1
 1
 1
 1
这说明x的前三个数据点属于簇2,而后四个数据点属于簇1。 kmeans函数也可以像下面这样使用:
复制代码 代码如下:

>> [class, C, sumd, D] = kmeans(x, 2)

class =
     2
     2
     2
     1
     1
     1
     1

C =
    4.0629    4.0845
   -0.1341    0.1201

sumd =
    1.2017
    0.2939

D =
   34.3727    0.0184
   29.5644    0.1858
   36.3511    0.0898
    0.1247   37.4801
    0.7537   24.0659
    0.1979   36.7666
    0.1256   36.2149

class依旧代表着每个数据点的分类;C包含最终的中心点,一行代表一个中心点;sumd代表着每个中心点与所属簇内各个数据点的距离之和;D的每一行也对应一个数据点,行中的数值依次是该数据点与各个中心点之间的距离,Kmeans默认使用的距离是欧几里得距离(参考资料[3])的平方值。kmeans函数使用的距离,也可以是曼哈顿距离(L1-距离),以及其他类型的距离,可以通过添加参数指定。

kmeans有几个缺点(这在很多资料上都有说明):

1、最终簇的类别数目(即中心点或者说种子点的数目)k并不一定能事先知道,所以如何选一个合适的k的值是一个问题。
2、最开始的种子点的选择的好坏会影响到聚类结果。
3、对噪声和离群点敏感。
4、等等。

2、kmeans++算法的基本思路

kmeans++算法的主要工作体现在种子点的选择上,基本原则是使得各个种子点之间的距离尽可能的大,但是又得排除噪声的影响。 以下为基本思路:

1、从输入的数据点集合(要求有k个聚类)中随机选择一个点作为第一个聚类中心
2、对于数据集中的每一个点x,计算它与最近聚类中心(指已选择的聚类中心)的距离D(x)
3、选择一个新的数据点作为新的聚类中心,选择的原则是:D(x)较大的点,被选取作为聚类中心的概率较大
4、重复2和3直到k个聚类中心被选出来
5、利用这k个初始的聚类中心来运行标准的k-means算法

假定数据点集合X有n个数据点,依次用X(1)、X(2)、……、X(n)表示,那么,在第2步中依次计算每个数据点与最近的种子点(聚类中心)的距离,依次得到D(1)、D(2)、……、D(n)构成的集合D。在D中,为了避免噪声,不能直接选取值最大的元素,应该选择值较大的元素,然后将其对应的数据点作为种子点。

如何选择值较大的元素呢,下面是一种思路(暂未找到最初的来源,在资料[2]等地方均有提及,笔者换了一种让自己更好理解的说法): 把集合D中的每个元素D(x)想象为一根线L(x),线的长度就是元素的值。将这些线依次按照L(1)、L(2)、……、L(n)的顺序连接起来,组成长线L。L(1)、L(2)、……、L(n)称为L的子线。根据概率的相关知识,如果我们在L上随机选择一个点,那么这个点所在的子线很有可能是比较长的子线,而这个子线对应的数据点就可以作为种子点。下文中kmeans++的两种实现均是这个原理。

3、python版本的kmeans++

在http://rosettacode.org/wiki/K-means%2B%2B_clustering 中能找到多种编程语言版本的Kmeans++实现。下面的内容是基于python的实现(中文注释是笔者添加的):

复制代码 代码如下:

from math import pi, sin, cos
from collections import namedtuple
from random import random, choice
from copy import copy

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

FLOAT_MAX = 1e100

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

def generate_points(npoints, radius):
    points = [Point() for _ in xrange(npoints)]

    # note: this is not a uniform 2-d distribution
    for p in points:
        r = random() * radius
        ang = random() * 2 * pi
        p.x = r * cos(ang)
        p.y = r * sin(ang)

    return points

def nearest_cluster_center(point, cluster_centers):
    """Distance and index of the closest cluster center"""
    def sqr_distance_2D(a, b):
        return (a.x - b.x) ** 2  +  (a.y - b.y) ** 2

    min_index = point.group
    min_dist = FLOAT_MAX

    for i, cc in enumerate(cluster_centers):
        d = sqr_distance_2D(cc, point)
        if min_dist > d:
            min_dist = d
            min_index = i

    return (min_index, min_dist)

'''
points是数据点,nclusters是给定的簇类数目
cluster_centers包含初始化的nclusters个中心点,开始都是对象->(0,0,0)
'''

def kpp(points, cluster_centers):
    cluster_centers[0] = copy(choice(points)) #随机选取第一个中心点
    d = [0.0 for _ in xrange(len(points))]  #列表,长度为len(points),保存每个点离最近的中心点的距离

    for i in xrange(1, len(cluster_centers)):  # i=1...len(c_c)-1
        sum = 0
        for j, p in enumerate(points):
            d[j] = nearest_cluster_center(p, cluster_centers[:i])[1] #第j个数据点p与各个中心点距离的最小值
            sum += d[j]

        sum *= random()

        for j, di in enumerate(d):
            sum -= di
            if sum > 0:
                continue
            cluster_centers[i] = copy(points[j])
            break

    for p in points:
        p.group = nearest_cluster_center(p, cluster_centers)[0]

'''
points是数据点,nclusters是给定的簇类数目
'''
def lloyd(points, nclusters):
    cluster_centers = [Point() for _ in xrange(nclusters)]  #根据指定的中心点个数,初始化中心点,均为(0,0,0)

    # call k++ init
    kpp(points, cluster_centers)   #选择初始种子点

    # 下面是kmeans
    lenpts10 = len(points) >> 10

    changed = 0
    while True:
        # group element for centroids are used as counters
        for cc in cluster_centers:
            cc.x = 0
            cc.y = 0
            cc.group = 0

        for p in points:
            cluster_centers[p.group].group += 1  #与该种子点在同一簇的数据点的个数
            cluster_centers[p.group].x += p.x
            cluster_centers[p.group].y += p.y

        for cc in cluster_centers:    #生成新的中心点
            cc.x /= cc.group
            cc.y /= cc.group

        # find closest centroid of each PointPtr
        changed = 0  #记录所属簇发生变化的数据点的个数
        for p in points:
            min_i = nearest_cluster_center(p, cluster_centers)[0]
            if min_i != p.group:
                changed += 1
                p.group = min_i

        # stop when 99.9% of points are good
        if changed             break

    for i, cc in enumerate(cluster_centers):
        cc.group = i

    return cluster_centers

def print_eps(points, cluster_centers, W=400, H=400):
    Color = namedtuple("Color", "r g b");

    colors = []
    for i in xrange(len(cluster_centers)):
        colors.append(Color((3 * (i + 1) % 11) / 11.0,
                            (7 * i % 11) / 11.0,
                            (9 * i % 11) / 11.0))

    max_x = max_y = -FLOAT_MAX
    min_x = min_y = FLOAT_MAX

    for p in points:
        if max_x         if min_x > p.x: min_x = p.x
        if max_y         if min_y > p.y: min_y = p.y

    scale = min(W / (max_x - min_x),
                H / (max_y - min_y))
    cx = (max_x + min_x) / 2
    cy = (max_y + min_y) / 2

    print "%%!PS-Adobe-3.0\n%%%%BoundingBox: -5 -5 %d %d" % (W + 10, H + 10)

    print ("/l {rlineto} def /m {rmoveto} def\n" +
           "/c { .25 sub exch .25 sub exch .5 0 360 arc fill } def\n" +
           "/s { moveto -2 0 m 2 2 l 2 -2 l -2 -2 l closepath " +
           "   gsave 1 setgray fill grestore gsave 3 setlinewidth" +
           " 1 setgray stroke grestore 0 setgray stroke }def")

    for i, cc in enumerate(cluster_centers):
        print ("%g %g %g setrgbcolor" %
               (colors[i].r, colors[i].g, colors[i].b))

        for p in points:
            if p.group != i:
                continue
            print ("%.3f %.3f c" % ((p.x - cx) * scale + W / 2,
                                    (p.y - cy) * scale + H / 2))

print ("n0 setgray %g %g s" % ((cc.x - cx) * スケール + W / 2,
) (cc.y - cy) * スケール + H / 2))

"n%%%%EOF" を印刷

def main():
npoints = 30000
k = 7 # # クラスター

ポイント = generated_points(npoints, 10)
クラスターセンター = lloyd(ポイント, k)
print_eps(ポイント, クラスターセンター)

メイン()

上記のコードで実装されたアルゴリズムは 2 次元データ用であるため、Point オブジェクトには 3 つの属性があります。つまり、x 軸の値、y 軸の値、およびクラスターの識別です。それは属します。関数 lloyd は kmeans++ アルゴリズムの全体的な実装であり、まず kpp 関数を通じて適切なシード ポイントを選択し、次にクラスタリング用のデータ セットに kmeans アルゴリズムを実装します。 kpp 関数の実装は、上記の kmeans++ の基本的な考え方のステップ 2、3、および 4 と完全に一致しています。


4. kmeans++ の Matlab バージョン

コードをコピー コードは次のとおりです。

function [L,C] = kmeanspp(X,k)
%KMEANS k-means++ アルゴリズムを使用して多変量データをクラスター化します。
% [L,C] = kmeans_pp(X,k) は、1 つのクラスを持つ 1 x size(X,2) のベクトル L を生成します
% X の列ごとのラベルと、各クラスに対応する
% 中心を含む size(X,1) 行 k 列の行列 C。

% バージョン: 2013-02-08
% 作成者: Laurent Sorber (Laurent.Sorber@cs.kuleuven.be)

L = [];
L1 = 0;

while length(unique(L)) ~= k

% k-means++ の初期化。
C = X(:,1+round(rand*(size(X,2)-1))); %size(X,2) はデータセット X です。データ点の数、C は中心点のセットです
L = ones(1,size(X,2));
for i = 2:k
D = X-C(:,L) ; % -1
D = Cumsum(sqrt(dot(D,D,1))); % D(end) == 0 の場合、シーケンス内の各データ点と中心点の間の距離を累積します。 C( :,i:k) = X(:,ones(1,k-i+1)); return; end
C(:,i) = X(:,find(rand [~,L] = max(bsxfun(@minus,2*real(C'*X),dot(C, C ,1).')); %Fortress、この文は各データ ポイントを分類します。
終了

% K 平均法アルゴリズム。

while any(L ~= L1)
L1 = L;
for i = 1:k, l = L==i; ) = sum ( C,1).'),[],1);
end

終了


この関数の実装はやや特殊です。パラメーター X はデータセットですが、各列はデータポイントとみなされ、パラメーター k は指定されたクラスター数です。戻り値 L は各データ ポイントの分類を示し、戻り値 C は最終的な中心点を保存します (1 つの列が中心点を表します)。テストします:


コードをコピーします コードは次のとおりです: >> x=[randn(3, 2)*.4;randn(4,2)*.5+ones(4,1)*[4 4]]
x =
-0.0497 0.5669
0.5959 0.2686
0.5636 -0.4830
4.3586 4.3634
4.8151 3.8483
4.2444 4.1469
4.5173 3.6064

>>> [L, C] = kmeanspp(x',2)L =

2 2 2 1 1 1 1
C =
4.4839 0.3699
3.9913 0.1175


さて、この実装を少し理解し始めて、MATLAB の知識を固めましょう。

独自の関数は、行列内のさまざまな値を取得するために使用されます。例:


コードをコピーします コードは次のとおりです: >> unique([1 3 3 4 4 5])
ans =
1 3 4 5
>> unique([1 3 3 ; 4 4 5] ])
ans =
1
3
4
5

所以循环 while length(unique(L)) ~= k 以得到了k个聚类为结束条件,不过一般情况下,这个循环一次就结束了,因为重点在这个循环中。

rand是返回在(0,1)这个区间的一个随机数。在注释%-1所在行,C被扩充了,被扩充的方法类似于下面:

复制代码 代码如下:

>> C =[];
>> C(1,1) = 1
C =
     1
>> C(2,1) = 2
C =
     1
     2
>> C(:,[1 1 1 1])
ans =
     1     1     1     1
     2     2     2     2
>> C(:,[1 1 1 1 2])
Index exceeds matrix dimensions.


C中第二个参数的元素1,其实是代表C的第一列数据,之所以在值2时候出现Index exceeds matrix dimensions.的错误,是因为C本身没有第二列。如果C有第二列了:

复制代码 代码如下:

>> C(2,2) = 3;
>> C(2,2) = 4;
>> C(:,[1 1 1 1 2])
ans =
     1     1     1     1     3
     2     2     2     2     4
dot函数是将两个矩阵点乘,然后把结果在某一维度相加:
复制代码 代码如下:

>> TT = [1 2 3 ; 4 5 6];
>> dot(TT,TT)
ans =
    17    29    45
>> dot(TT,TT,1 )
ans =
    17    29    45
cumsum是累加函数:
复制代码 代码如下:

>> cumsum([1 2 3])
ans =
     1     3     6
>> cumsum([1 2 3; 4 5 6])
ans =
     1     2     3
     5     7     9
max函数可以返回两个值,第二个代表的是max数的索引位置:
复制代码 代码如下:

>> [~, L] = max([1 2 3])
L =
     3
>> [~,L] = max([1 2 3;2 3 4])
L =
     2     2     2
其中~是占位符。

关于bsxfun函数,官方文档指出:

复制代码 代码如下:

C = bsxfun(fun,A,B) applies the element-by-element binary operation specified by the function handle fun to arrays A and B, with singleton expansion enabled
其中参数fun是函数句柄,关于函数句柄见资料[9]。下面是bsxfun的一个示例:
复制代码 代码如下:
>> A= [1 2 3;2 3 4]
A =
     1     2     3
     2     3     4
>> B=[6;7]
B =
     6
     7
>> bsxfun(@minus,A,B)
ans =
    -5    -4    -3
    -5    -4    -3
对于:
复制代码 代码如下:

[~,L] = max(bsxfun(@minus,2*real(C'*X),dot(C,C,1).'));
max的参数是这样一个矩阵,矩阵有n列,n也是数据点的个数,每一列代表着对应的数据点与各个中心点之间的距离的相反数。不过这个距离有些与众不同,算是欧几里得距离的变形。

データ点が 2 次元で、特定のデータ点が (x1, y1)、特定の中心点が (c1, d1) であると仮定すると、bsxfun(@minus,2real(C'X), dot(C ,C,1).') の計算では、データ点と中心点の間の距離は 2c1x1 + 2d1y1 -c1.^2 - c2.^2 となり、x1.^2 + y1 に変換できます。 ^2 - (c1-x1 ).^2 - (d1-y1).^2。各列について、データ点と各中心点の間の計算であるため、x1.^2 + y1.^2 は無視でき、最終的な計算結果はユークリッド距離の 2 乗の逆数になります。これは、データ ポイントが属するクラスターがそのデータ ポイントに最も近い中心ポイントに依存するため、max を使用する合理性も示しています。距離が逆の場合、それが最大値を持つポイントになるはずです。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Python:ゲーム、GUIなどPython:ゲーム、GUIなどApr 13, 2025 am 12:14 AM

PythonはゲームとGUI開発に優れています。 1)ゲーム開発は、2Dゲームの作成に適した図面、オーディオ、その他の機能を提供し、Pygameを使用します。 2)GUI開発は、TKINTERまたはPYQTを選択できます。 TKINTERはシンプルで使いやすく、PYQTは豊富な機能を備えており、専門能力開発に適しています。

Python vs. C:比較されたアプリケーションとユースケースPython vs. C:比較されたアプリケーションとユースケースApr 12, 2025 am 12:01 AM

Pythonは、データサイエンス、Web開発、自動化タスクに適していますが、Cはシステムプログラミング、ゲーム開発、組み込みシステムに適しています。 Pythonは、そのシンプルさと強力なエコシステムで知られていますが、Cは高性能および基礎となる制御機能で知られています。

2時間のPython計画:現実的なアプローチ2時間のPython計画:現実的なアプローチApr 11, 2025 am 12:04 AM

2時間以内にPythonの基本的なプログラミングの概念とスキルを学ぶことができます。 1.変数とデータ型、2。マスターコントロールフロー(条件付きステートメントとループ)、3。機能の定義と使用を理解する4。

Python:主要なアプリケーションの調査Python:主要なアプリケーションの調査Apr 10, 2025 am 09:41 AM

Pythonは、Web開発、データサイエンス、機械学習、自動化、スクリプトの分野で広く使用されています。 1)Web開発では、DjangoおよびFlask Frameworksが開発プロセスを簡素化します。 2)データサイエンスと機械学習の分野では、Numpy、Pandas、Scikit-Learn、Tensorflowライブラリが強力なサポートを提供します。 3)自動化とスクリプトの観点から、Pythonは自動テストやシステム管理などのタスクに適しています。

2時間でどのくらいのPythonを学ぶことができますか?2時間でどのくらいのPythonを学ぶことができますか?Apr 09, 2025 pm 04:33 PM

2時間以内にPythonの基本を学ぶことができます。 1。変数とデータ型を学習します。2。ステートメントやループの場合などのマスター制御構造、3。関数の定義と使用を理解します。これらは、簡単なPythonプログラムの作成を開始するのに役立ちます。

プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は?プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は?Apr 02, 2025 am 07:18 AM

10時間以内にコンピューター初心者プログラミングの基本を教える方法は?コンピューター初心者にプログラミングの知識を教えるのに10時間しかない場合、何を教えることを選びますか...

中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか?中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか?Apr 02, 2025 am 07:15 AM

fiddlereveryversings for the-middleの測定値を使用するときに検出されないようにする方法

Python 3.6にピクルスファイルをロードするときに「__Builtin__」モジュールが見つからない場合はどうすればよいですか?Python 3.6にピクルスファイルをロードするときに「__Builtin__」モジュールが見つからない場合はどうすればよいですか?Apr 02, 2025 am 07:12 AM

Python 3.6のピクルスファイルのロードレポートエラー:modulenotFounderror:nomodulenamed ...

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール