一維數組的 K-Means 聚類算法理解


剛看了這個算法,理解如下,放在這里,備忘,如有錯誤的地方,請指出,謝謝

 


需要做聚類的數組我們稱之為【源數組】
需要一個分組個數K變量來標記需要分多少個組,這個數組我們稱之為【聚類中心數組】及
一個緩存臨時聚類中心的數組,我們稱之為【緩存聚類中心數組】
然后初始化一個K長度的數組,值隨機(盡量分布在原數組的更大的區間以便計算),用於和源數組進行比對計算。

下面是計算的部分:
死循環遍歷對源數據進行分組。

分組內遍歷原數組的每個元素與聚類中心的每個元素的距離(差值的絕對值),將最小距離的聚類中心數組下標緩存的臨時變量臨時變量數組A中(長度=原數組),
創建二維數組,我們稱之為【分組數組】 [聚類中心數組長度][源數組中分類的值],
遍歷臨時變量數組A,使用A的小標拿到原數組對應的值,賦值給分組數組。
具體公式如:
分組數組[A[i]].add(原數組[i]);
返回分組數組

對分組后的數組計算中間值存入緩存聚類中心數組,比較緩存劇烈數組和聚類數組,是否位置一樣,值一樣,如果一樣跳出死循環,分類結束,
否則將臨時劇烈中心數組賦值給聚類中心數組進行下次循環

 

別笑!語文從來沒及格過,表達能力就這樣了。。。。。。。。不明白我說的啥,那么就看代碼吧。

 

下面是c#代碼,如果需要java代碼,請看http://www.oschina.net/code/snippet_42411_2527

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace K_MeansTest
{
    class Program
    {
        static void Main(string[] args)
        {
            double[] p = { 1, 2, 3, 5, 6, 7, 9, 10, 11,20,21,22,23,27,40,41,42,43,61,62,63, 100, 150, 200, 1000 };
            int k = 5;
            double[][] g;
            g = cluster(p, k);
            for (int i = 0; i < g.Length; i++)
            {
                for (int j = 0; j < g[i].Length; j++)
                {
                    Console.WriteLine(g[i][j]);
                }
                Console.WriteLine("----------------------");
            }
            Console.ReadKey();
        }

        /*
    * 聚類函數主體。
    * 針對一維 double 數組。指定聚類數目 k。
    * 將數據聚成 k 類。
    */
        public static double[][] cluster(double[] p, int k)
        {
            // 存放聚類舊的聚類中心
            double[] c = new double[k];
            // 存放新計算的聚類中心
            double[] nc = new double[k];
            // 存放放回結果
            double[][] g;
            // 初始化聚類中心
            // 經典方法是隨機選取 k 個
            // 本例中采用前 k 個作為聚類中心
            // 聚類中心的選取不影響最終結果
            for (int i = 0; i < k; i++)
                c[i] = p[i];
            // 循環聚類,更新聚類中心
            // 到聚類中心不變為止
            while (true)
            {
                // 根據聚類中心將元素分類
                g = group(p, c);
                // 計算分類后的聚類中心
                for (int i = 0; i < g.Length; i++)
                {
                    nc[i] = center(g[i]);
                }
                // 如果聚類中心不同
                if (!equal(nc, c))
                {
                    // 為下一次聚類准備
                    c = nc;
                    nc = new double[k];
                }
                else // 聚類結束
                    break;
            }
            // 返回聚類結果
            return g;
        }
        /*
         * 聚類中心函數
         * 簡單的一維聚類返回其算數平均值
         * 可擴展
         */
        public static double center(double[] p)
        {
            return sum(p) / p.Length;
        }
        /*
         * 給定 double 型數組 p 和聚類中心 c。
         * 根據 c 將 p 中元素聚類。返回二維數組。
         * 存放各組元素。
         */
        public static double[][] group(double[] p, double[] c)
        {
            // 中間變量,用來分組標記
            int[] gi = new int[p.Length];
            // 考察每一個元素 pi 同聚類中心 cj 的距離
            // pi 與 cj 的距離最小則歸為 j 類
            for (int i = 0; i < p.Length; i++)
            {
                // 存放距離
                double[] d = new double[c.Length];
                // 計算到每個聚類中心的距離
                for (int j = 0; j < c.Length; j++)
                {
                    d[j] = distance(p[i], c[j]);
                }
                // 找出最小距離
                int ci = min(d);
                // 標記屬於哪一組
                gi[i] = ci;
            }
            // 存放分組結果
            double[][] g = new double[c.Length][];
            // 遍歷每個聚類中心,分組
            for (int i = 0; i < c.Length; i++)
            {
                // 中間變量,記錄聚類后每一組的大小
                int s = 0;
                // 計算每一組的長度
                for (int j = 0; j < gi.Length; j++)
                    if (gi[j] == i)
                        s++;
                // 存儲每一組的成員
                g[i] = new double[s];
                s = 0;
                // 根據分組標記將各元素歸位
                for (int j = 0; j < gi.Length; j++)
                    if (gi[j] == i)
                    {
                        g[i][s] = p[j];
                        s++;
                    }
            }
            // 返回分組結果
            return g;
        }

        /*
         * 計算兩個點之間的距離, 這里采用最簡單得一維歐氏距離, 可擴展。
         */
        public static double distance(double x, double y)
        {
            return Math.Abs(x - y);
        }

        /*
         * 返回給定 double 數組各元素之和。
         */
        public static double sum(double[] p)
        {
            double sum = 0.0;
            for (int i = 0; i < p.Length; i++)
                sum += p[i];
            return sum;
        }

        /*
         * 給定 double 類型數組,返回最小值得下標。
         */
        public static int min(double[] p)
        {
            int i = 0;
            double m = p[0];
            for (int j = 1; j < p.Length; j++)
            {
                if (p[j] < m)
                {
                    i = j;
                    m = p[j];
                }
            }
            return i;
        }

        /*
         * 判斷兩個 double 數組是否相等。 長度一樣且對應位置值相同返回真。
         */
        public static bool equal(double[] a, double[] b)
        {
            if (a.Length != b.Length)
                return false;
            else
            {
                for (int i = 0; i < a.Length; i++)
                {
                    if (a[i] != b[i])
                        return false;
                }
            }
            return true;
        }
    }
}

結果如下

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM