摘要:文本聚类是搜索引擎和语义web的基本技术,这次本蛙和大家一起学习一下简单的文本聚类算法,可能不能直接用于实际应用中,但对于想学搜索技术的初学者还是有一定入门作用的。这里会用到TF/IDF权重,用余弦夹角计算文本相似度,用方差计算两个数据间欧式距离,用k-means进行数据聚类等数学和统计知识。关于这些概念可以去google,或者参考文本后的参考链接。


蛙蛙推荐:蛙蛙教你文本聚类

摘要:文本聚类是搜索引擎和语义web的基本技术,这次本蛙和大家一起学习一下简单的文本聚类算法,可能不能直接用于实际应用中,但对于想学搜索技术的初学者还是有一定入门作用的。这里会用到TF/IDF权重,用余弦夹角计算文本相似度,用方差计算两个数据间欧式距离,用k-means进行数据聚类等数学和统计知识。关于这些概念可以去google,或者参考文本后的参考链接。

思路:计算两篇文档的相似度,最简单的做法就是用提取文档的TF/IDF权重,然后用余弦定理计算两个多维向量的距离。能计算两个文本间的距离后,用标准的k-means算法就可以实现文本聚类了。

测试:首先我们准备以下数据

===================

奥运 拳击 入场券 基本 分罄 邹市明 夺冠 对手 浮出 水面

股民 要 清楚 自己 的 目的

印花税 之 股民 四季

杭州 股民 放 鞭炮 庆祝 印花税 下调

残疾 女 青年 入围 奥运 游泳 比赛 创 奥运 历史 两 项 第一

介绍 一 个 ASP.net MVC 系列 教程

在 asp.net 中 实现 观察者 模式 ,或 有 更 好 的 方法 (续)

输 大钱 的 股民 给 我们 启迪

Asp.Net 页面 执行 流程 分析

运动员 行李 将 “后 上 先 下” 奥运 相关 人员 行李 实名制

asp.net 控件 开发 显示 控件 内容

奥运 票务 网上 成功 订票 后 应 及时 到 银行 代售 网点 付款

某 心理 健康 站 开张 后 首 个 咨询 者 是 位 新 股民

ASP.NET 自定义 控件 复杂 属性 声明 持久性 浅析

==================

很明显以上数据可以分为三类:asp.net,奥运和股民,我们就写程序来实现它,各种算法的原理网上都有,我就大概只贴代码,声明一下,部分代码是从网上直接抄的,k-means代码是我从一篇文章的java示例代码转换过来的,我给代码加了不少注释,希望能帮助大家理解。

以下是入口函数

蛙蛙推荐:蛙蛙教你文本聚类_聚类static void Main(string[] args)

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_02蛙蛙推荐:蛙蛙教你文本聚类_数据_03蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    //1、获取文档输入

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    string[] docs = getInputDocs("input.txt");

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    if (docs.Length < 1)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        Console.WriteLine("没有文档输入");

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        Console.Read();

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        return;

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    //2、初始化TFIDF测量器,用来生产每个文档的TFIDF权重

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    TFIDFMeasure tf = new TFIDFMeasure(docs, new Tokeniser());

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    int K = 3; //聚成3个聚类

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    //3、生成k-means的输入数据,是一个联合数组,第一维表示文档个数,

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    //第二维表示所有文档分出来的所有词

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    double[][] data = new double[docs.Length][];

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    int docCount = docs.Length; //文档个数

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    int dimension = tf.NumTerms;//所有词的数目

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    for (int i = 0; i < docCount; i++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        for (int j = 0; j < dimension; j++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09        蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            data[i] = tf.GetTermVector2(i); //获取第i个文档的TFIDF权重向量

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14        }

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    //4、初始化k-means算法,第一个参数表示输入数据,第二个参数表示要聚成几个类

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    WawaKMeans kmeans = new WawaKMeans(data, K);

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    //5、开始迭代

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    kmeans.Start();

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    //6、获取聚类结果并输出

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    WawaCluster[] clusters = kmeans.Clusters;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    foreach (WawaCluster cluster in clusters)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        List<int> members = cluster.CurrentMembership;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        Console.WriteLine("-----------------");

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        foreach (int i in members)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09        蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            Console.WriteLine(docs[i]);

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14        }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    Console.Read();

蛙蛙推荐:蛙蛙教你文本聚类_聚类_60}

蛙蛙推荐:蛙蛙教你文本聚类_聚类

蛙蛙推荐:蛙蛙教你文本聚类_聚类


以下是分词器的主要代码

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_02蛙蛙推荐:蛙蛙教你文本聚类_数据_03/**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05/// 以空白字符进行简单分词,并忽略大小写,

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05/// 实际情况中可以用其它中文分词算法

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05/// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05/// <param name="input"></param>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_60/// <returns></returns>

蛙蛙推荐:蛙蛙教你文本聚类_聚类public IList<string> Partition(string input)

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_02蛙蛙推荐:蛙蛙教你文本聚类_数据_03蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05 Regex r=new Regex("([ \\t{}():;. \n])");  

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05 input=input.ToLower() ;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05 String [] tokens=r.Split(input);          

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05 List<string> filter=new  List<string>() ;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05 for (int i=0; i < tokens.Length ; i++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09 蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05  MatchCollection mc=r.Matches(tokens[i]);

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05  if (mc.Count <= 0 && tokens[i].Trim().Length > 0       

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05   && !StopWordsHandler.IsStopword (tokens[i]) )        

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05   filter.Add(tokens[i]) ;

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14        }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05 

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05 return filter.ToArray();

蛙蛙推荐:蛙蛙教你文本聚类_聚类_60}

蛙蛙推荐:蛙蛙教你文本聚类_聚类

蛙蛙推荐:蛙蛙教你文本聚类_聚类


以下是kmeans算法的基本代码

蛙蛙推荐:蛙蛙教你文本聚类_聚类public class WawaKMeans

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_02蛙蛙推荐:蛙蛙教你文本聚类_数据_03蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 数据的数量

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    readonly int _coordCount;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 原始数据

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    readonly double[][] _coordinates;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 聚类的数量

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    readonly int _k;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 聚类

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    private readonly WawaCluster[] _clusters;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    internal WawaCluster[] Clusters

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09        get 蛙蛙推荐:蛙蛙教你文本聚类_数据_04{ return _clusters; }

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    } 

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 定义一个变量用于记录和跟踪每个资料点属于哪个群聚类

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// _clusterAssignments[j]=i;// 表示第 j 个资料点对象属于第 i 个群聚类

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    readonly int[] _clusterAssignments;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 定义一个变量用于记录和跟踪每个资料点离聚类最近

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    private readonly int[] _nearestCluster;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 定义一个变量,来表示资料点到中心点的距离,

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 其中—_distanceCache[i][j]表示第i个资料点到第j个群聚对象中心点的距离;

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    private readonly double[,] _distanceCache;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 用来初始化的随机种子

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    private static readonly Random _rnd = new Random(1);

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    public WawaKMeans(double[][] data, int K)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        _coordinates = data;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        _coordCount = data.Length;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        _k = K;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        _clusters = new WawaCluster[K];

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        _clusterAssignments = new int[_coordCount];

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        _nearestCluster = new int[_coordCount];

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        _distanceCache = new double[_coordCount,data.Length];

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        InitRandom();

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    public void Start()

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        int iter = 0;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        while (true)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09        蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            Console.WriteLine("Iteration " + (iter++) + "蛙蛙推荐:蛙蛙教你文本聚类_数据_04");

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            //1、重新计算每个聚类的均值

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            for (int i = 0; i < _k; i++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09            蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                _clusters[i].UpdateMean(_coordinates);

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14            }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            //2、计算每个数据和每个聚类中心的距离

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            for (int i = 0; i < _coordCount; i++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09            蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                for (int j = 0; j < _k; j++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09                蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                    double dist = getDistance(_coordinates[i], _clusters[j].Mean);

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                    _distanceCache[i,j] = dist;

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14                }

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14            }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            //3、计算每个数据离哪个聚类最近

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            for (int i = 0; i < _coordCount; i++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09            蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                _nearestCluster[i] = nearestCluster(i);

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14            }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            //4、比较每个数据最近的聚类是否就是它所属的聚类

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            //如果全相等表示所有的点已经是最佳距离了,直接返回;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            int k = 0;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            for (int i = 0; i < _coordCount; i++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09            蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                if (_nearestCluster[i] == _clusterAssignments[i])

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                    k++;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14            }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            if (k == _coordCount)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                break;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            //5、否则需要重新调整资料点和群聚类的关系,调整完毕后再重新开始循环;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            //需要修改每个聚类的成员和表示某个数据属于哪个聚类的变量

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            for (int j = 0; j < _k; j++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09            蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                _clusters[j].CurrentMembership.Clear();

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14            }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            for (int i = 0; i < _coordCount; i++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09            蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                _clusters[_nearestCluster[i]].CurrentMembership.Add(i);

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                _clusterAssignments[i] = _nearestCluster[i];

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14            }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14        }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 计算某个数据离哪个聚类最近

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// <param name="ndx"></param>

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// <returns></returns>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    int nearestCluster(int ndx)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        int nearest = -1;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        double min = Double.MaxValue;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        for (int c = 0; c < _k; c++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09        蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            double d = _distanceCache[ndx,c];

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            if (d < min)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09            蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                min = d;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                nearest = c;

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14            }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05      

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14        }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        if(nearest==-1)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09        蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            ;

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14        }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        return nearest;

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 计算某数据离某聚类中心的距离

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// <param name="coord"></param>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// <param name="center"></param>

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// <returns></returns>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    static double getDistance(double[] coord, double[] center)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //int len = coord.Length;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //double sumSquared = 0.0;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //for (int i = 0; i < len; i++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //    double v = coord[i] - center[i];

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //    sumSquared += v * v; //平方差

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //}

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //return Math.Sqrt(sumSquared);

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //也可以用余弦夹角来计算某数据离某聚类中心的距离

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        return 1- TermVector.ComputeCosineSimilarity(coord, center);

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    } 

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 随机初始化k个聚类

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    private void InitRandom()

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        for (int i = 0; i < _k; i++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09        蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            int temp = _rnd.Next(_coordCount);

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            _clusterAssignments[temp] = i; //记录第temp个资料属于第i个聚类

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            _clusters[i] = new WawaCluster(temp,_coordinates[temp]);

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14        }

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_60}

蛙蛙推荐:蛙蛙教你文本聚类_聚类

蛙蛙推荐:蛙蛙教你文本聚类_聚类


以下是聚类实体类的定义

蛙蛙推荐:蛙蛙教你文本聚类_聚类internal class WawaCluster

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_02蛙蛙推荐:蛙蛙教你文本聚类_数据_03蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    public WawaCluster(int dataindex,double[] data)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        CurrentMembership.Add(dataindex);

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        Mean = data;

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 该聚类的数据成员索引

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    internal List<int> CurrentMembership = new List<int>();

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 该聚类的中心

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    internal double[] Mean;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    /**//// <summary>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// 该方法计算聚类对象的均值 

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    /// </summary>

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    /// <param name="coordinates"></param>

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05    public void UpdateMean(double[][] coordinates)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09    蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        // 根据 mCurrentMembership 取得原始资料点对象 coord ,该对象是 coordinates 的一个子集;

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //然后取出该子集的均值;取均值的算法很简单,可以把 coordinates 想象成一个 m*n 的距阵 ,

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        //每个均值就是每个纵向列的取和平均值 , //该值保存在 mCenter 中

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05        for (int i = 0; i < CurrentMembership.Count; i++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09        蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            double[] coord = coordinates[CurrentMembership[i]];

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            for (int j = 0; j < coord.Length; j++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09            蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                Mean[j] += coord[j]; // 得到每个纵向列的和;

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14            }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05            for (int k = 0; k < Mean.Length; k++)

蛙蛙推荐:蛙蛙教你文本聚类_聚类_08蛙蛙推荐:蛙蛙教你文本聚类_asp.net_09            蛙蛙推荐:蛙蛙教你文本聚类_数据_04{

蛙蛙推荐:蛙蛙教你文本聚类_聚类_05                Mean[k] /= coord.Length; // 对每个纵向列取平均值

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14            }

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14        }

蛙蛙推荐:蛙蛙教你文本聚类_asp.net_14    }

蛙蛙推荐:蛙蛙教你文本聚类_聚类_60}

蛙蛙推荐:蛙蛙教你文本聚类_聚类

蛙蛙推荐:蛙蛙教你文本聚类_聚类


计算TF/IDF和利用余弦定理计算相似度的代码见完整版的代码下载,那两部分都是外国人写的,里面有它的联系方式,不懂的可以问他,反正我差不多懂了。

下面看看咱们的测试结果:

Iteration 0...

Iteration 1...

Iteration 2...

-----------------

奥运 拳击 入场券 基本 分罄 邹市明 夺冠 对手 浮出 水面

杭州 股民 放 鞭炮 庆祝 印花税 下调

残疾 女 青年 入围 奥运 游泳 比赛 创 奥运 历史 两 项 第一

运动员 行李 将 “后 上 先 下” 奥运 相关 人员 行李 实名制

奥运 票务 网上 成功 订票 后 应 及时 到 银行 代售 网点 付款

-----------------

股民 要 清楚 自己 的 目的

印花税 之 股民 四季

输 大钱 的 股民 给 我们 启迪

某 心理 健康 站 开张 后 首 个 咨询 者 是 位 新 股民

-----------------

介绍 一 个 ASP.net MVC 系列 教程

在 asp.net 中 实现 观察者 模式 ,或 有 更 好 的 方法 (续)

Asp.Net 页面 执行 流程 分析

asp.net 控件 开发 显示 控件 内容

ASP.NET 自定义 控件 复杂 属性 声明 持久性 浅析聚类聚的非常准确,而且只迭代了3次,模型就收敛了,当然了这是最理想的效果,其实聚类的结果受好多种因素制约,提取特征的算法,随机初始化函数,kmeans算法的实现等,都有优化的地方,不信你把输入的数据的顺序改改,聚类结果就不一样了,或者把随机数的种子变一下,结果也不一样,k-means算法加入一些变异系数的调整,结果也不一样,提取特征的地方不用TF/IDF权重算法用别的,结果肯定也不一样。

完整代码里还有另一组测试数据,结果也很不错,我的意思是我的算法不是针对一组测试数据,而是针对好多数据都有不错的结果。

总结:数学和英语真是写程序之根本呀,弄这个东西遇到了好多英语单词不会,查还查不出来,也理解不了,最后google一看,是个数学专用词,再搜索这个数学专用词的中文解释,发现还是理解不了那数学原理。所以还是得多学习数学和英语。

参考链接:

K-MEANS算法

​ http://beauty9235.javaeye.com/blog/161675​

什么是变异系数

​ http://zhidao.baidu.com/question/15013015.html​

TF/IDF实现

​ http://www.codeproject.com/KB/cs/tfidf.aspx​


源码下载:​​WawaTextCluster.zip​