基于K-Means的文本聚类算法

简介:
源代码下载:TDIDF_Demo.rar 
       声明:本文代码思路完全来自蛙蛙池塘的博客,只为技术交流用途,无其他目的

      昨天有幸拜读了蛙蛙池塘的《蛙蛙推荐:蛙蛙教你文本聚类》这篇文章,受益匪浅,于是今天就动手尝试照着他的C#代码,用C++和STL标准库重新实现一遍,因此就有了这篇文章。本文将重新温习蛙蛙池塘那篇文章,并且加入我个人在用C++重写这份代码过程中学到的一些知识。

TF-IDF(term frequency–inverse document frequency)

     这是一种用于信息检索的一种常用加权技术。它是一种统计方法,用以评估一个字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。

假如一篇文件的总词语数是100个,而词语“母牛”出现了3次,那么“母牛”一词在该文件中的词频就是 0.03 (3/100)。一个计算文件频率 (DF) 的方法是测定有多少份文件出现过“母牛”一词,然后除以文件集里包含的文件总数。所以,如果“母牛”一词在1,000份文件出现过,而文件总数是 10,000,000份的话,其文件频率就是 0.0001 (1000/10,000,000)。最后,TF-IDF分数就可以由计算词频除以文件频率而得到。以上面的例子来说,“母牛”一词在该文件集的TF- IDF分数会是 300 (0.03/0.0001)。这条公式的另一个形式是将文件频率取对数。

具体的计算原理,请参考维基百科tf–idf条目。下面简单介绍下基本的计算步骤:

1,文档预处理:1)文档分词;2)移除停用词;3)单词正规化处理

2,分出的单词就作为索引项(或单词表),它们代表的就是向量空间的项向量

3,计算项权值:这包括要计算1)词频 ; 2)倒排文件频率;3)TF-IDF权值

4,计算文档之间的相似度,一般用余弦相似度(cosine similarity)一同使用于向量空间模型中,用以判断两份文件之间的相似性

复制代码
#include "ITokeniser.h"
#include <map>
class TFIDFMeasure
{
private:
    StrVec _docs;//文档集合,每一行字符串代表一份文档
    int _numDocs;//文档数目
    int _numTerms;//单词数目
    StrVec _terms;//单词集合
    Int2DVec _termFreq;//每个单词出现在每份文档中的频率
    Double2DVec  _termWeight;//每个单词在每份文档的权重
    IntVec _maxTermFreq;//记录每一份文档的最大词频
    IntVec _docFreq;//出现单词的文档频率
    ITokeniser* _tokenizer;//分词器
    map<string,int> _wordsIndex;//单词映射表,保存每一个单词及其对应的下标
public:
    TFIDFMeasure(const StrVec& documents,ITokeniser* tokeniser);
public:
    ~TFIDFMeasure(void);
protected:
    void Init();//初始化TF-IDF计算器
    void GenerateTerms(const StrVec& docs,StrVec& terms);//分词处理
    void GenerateTermFrequency();//计算词频
    void GenerateTermWeight();//计算词的权重
    void GetWordFrequency(string& input,map<string,int>& freq); //实际统计词频函数
    int CountWords(string& word, const StrVec& words);//统计词数
    int GetTermIndex(const string& term);//查询词语对应的下标
    double ComputeTermWeight(int term, int doc);//计算词语在指定文档中的权重值
    double GetTermFrequency(int term, int doc);//获取词语在指定文档的词频
    double GetInverseDocumentFrequency(int term);//计算倒排文件频率
public:
    inline int NumTerms()const
    {
        return this->_numTerms;
    }
    void  GetTermVector(int doc,DoubleVec& vec);//获取项向量
};
复制代码
 

TF-IDF具体实现代码
分词算法

      为了便于使用不同的分词算法,我们定义一个抽象的分词算法接口,具体的分词算法由用户自行实现

class ITokeniser
{
public:
    virtual void Partition(string input,StrVec& retWords)=0;//分词算法
};
     这里只实现了一个最简单的空格符分词算法:

复制代码
#include "Tokeniser.h"
#include "StopWordsHandler.h"

Tokeniser::Tokeniser(void)
{
}
Tokeniser::~Tokeniser(void)
{
}
void Tokeniser::Partition(string input,StrVec& retWords)
{//分词算法,input为输入串,retWords为处理后所分开的单词,这里就简单化处理了,以空格符为分隔符进行分词
    transform(input.begin(),input.end(),input.begin(),tolower);
    string::iterator start = input.begin();
    string::iterator end = input.end();
    StopWordsHandler stopHandler;
    do 
    {
        string temp;
        pos = find(start,input.end(),' ');//找到分隔符
        copy(start,end,back_inserter(temp));
        if (!stopHandler.IsStopWord(temp))
        {//不是停用词则保存
            retWords.push_back(temp);//保存分出的单词
        }
        if (end == input.end())
        {//最后一个单词了
            break;
        }
         start = ++end;
    } while (end != input.end());
}
复制代码
停用词处理

      去掉文档中无意思的词语也是必须的一项工作,这里简单的定义了一些常见的停用词,并根据这些常用停用词在分词时进行判断

复制代码
#include "StopWordsHandler.h"
string stopWordsList[] ={"的", "我们","要","自己","之","将","“","”",",","(",")","后","应","到","某","后",
"个","是","位","新","一","两","在","中","或","有","更","好",""};//常用停用词
int stopWordsLen = sizeof(stopWordsList)/sizeof(stopWordsList[0]);

StopWordsHandler::StopWordsHandler(void)
{
    for (int i=0;i<stopWordsLen;++i)
    {
        stopWords.push_back(stopWordsList[i]);
    }
}
StopWordsHandler::~StopWordsHandler(void)
{
}
bool StopWordsHandler::IsStopWord(string& str)
{//是否是停用词
    transform(str.begin(),str.end(),str.begin(),tolower);//确保小写化
    return find(stopWords.begin(),stopWords.end(),str)!=stopWords.end();
}
复制代码
K-Means算法

       k-means 算法接受输入量 k ;然后将n个数据对象划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。聚类相似度是利用各聚类中对象的均值所获得一个“中心对象”(引力中心)来进行计算的。

 k-means 算法的工作过程说明如下:首先从n个数据对象任意选择 k 个对象作为初始聚类中心;而对于所剩下其它对象,则根据它们与这些聚类中心的相似度(距离),分别将它们分配给与其最相似的(聚类中心所代表的)聚类;然 后再计算每个所获新聚类的聚类中心(该聚类中所有对象的均值);不断重复这一过程直到标准测度函数开始收敛为止。一般都采用均方差作为标准测度函数. k个聚类具有以下特点:各聚类本身尽可能的紧凑,而各聚类之间尽可能的分开。  

复制代码
#include "Common.h"

class Cluster;

class KMeans
{
public:
    vector<Cluster*> _clusters;//聚类
private:
    int _coordCount;//数据的数量
    Double2DVec _coordinates;//原始数据
    int _k;//聚类的数量
    //定义一个变量用于记录和跟踪每个资料点属于哪个群聚类
    // _clusterAssignments[j]=i; 表示第j 个资料点对象属于第i 个群聚类
    IntVec _clusterAssignments;
    // 定义一个变量用于记录和跟踪每个资料点离聚类最近
    IntVec _nearestCluster;
    /// 定义一个变量,来表示资料点到中心点的距离,
    /// 其中—_distanceCache[i][j]表示第i个资料点到第j个群聚对象中心点的距离;
    Double2DVec _distanceCache;
    void InitRandom();
    static double getDistance(const DoubleVec& coord, const DoubleVec& center);
    int NearestCluster(int ndx);

public:
    KMeans(Double2DVec& data, int K);
    void Start();
public:
    ~KMeans(void);
};
复制代码
 

K-Means算法具体实现
最后使用《蛙蛙推荐:蛙蛙教你文本聚类》这篇文章中的数据测试所得:



Reference

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

2,Term frequency/Inverse document frequency implementation in C#

3, 维基百科tf–idf条目

4, K-Means算法java实现

 

附:

最后我想请教一个问题:蛙蛙池塘的代码中分词算法使用了一个正则表达式

Regex r=new Regex("([ ""t{}():;. "n])");

它产生的结果是将”asp.net”分成了两个单词”asp”和”net”,请问,为什么不直接将其看作是一个单词”asp.net”呢?



本文转自Phinecos(洞庭散人)博客园博客,原文链接http://www.cnblogs.com/phinecos/archive/2008/09/06/1285646.html,如需转载请自行联系原作者
目录
相关文章
|
7月前
|
数据采集 机器学习/深度学习 算法
|
4月前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
212 6
|
19天前
|
监控 算法 安全
内网桌面监控软件深度解析:基于 Python 实现的 K-Means 算法研究
内网桌面监控软件通过实时监测员工操作,保障企业信息安全并提升效率。本文深入探讨K-Means聚类算法在该软件中的应用,解析其原理与实现。K-Means通过迭代更新簇中心,将数据划分为K个簇类,适用于行为分析、异常检测、资源优化及安全威胁识别等场景。文中提供了Python代码示例,展示如何实现K-Means算法,并模拟内网监控数据进行聚类分析。
35 10
|
7月前
|
数据采集 机器学习/深度学习 算法
【优秀设计案例】基于K-Means聚类算法的球员数据聚类分析设计与实现
本文通过K-Means聚类算法对NBA球员数据进行聚类分析,旨在揭示球员间的相似性和差异性,为球队管理、战术决策和球员评估提供数据支持,并通过特征工程和结果可视化深入理解球员表现和潜力。
218 1
【优秀设计案例】基于K-Means聚类算法的球员数据聚类分析设计与实现
|
4月前
|
算法 数据挖掘 数据安全/隐私保护
基于FCM模糊聚类算法的图像分割matlab仿真
本项目展示了基于模糊C均值(FCM)算法的图像分割技术。算法运行效果良好,无水印。使用MATLAB 2022a开发,提供完整代码及中文注释,附带操作步骤视频。FCM算法通过隶属度矩阵和聚类中心矩阵实现图像分割,适用于灰度和彩色图像,广泛应用于医学影像、遥感图像等领域。
|
5月前
|
算法 数据挖掘
基于粒子群优化算法的图象聚类识别matlab仿真
该程序基于粒子群优化(PSO)算法实现图像聚类识别,能识别0~9的数字图片。在MATLAB2017B环境下运行,通过特征提取、PSO优化找到最佳聚类中心,提高识别准确性。PSO模拟鸟群捕食行为,通过粒子间的协作优化搜索过程。程序包括图片读取、特征提取、聚类分析及结果展示等步骤,实现了高效的图像识别。
|
6月前
|
机器学习/深度学习 存储 人工智能
文本情感识别分析系统Python+SVM分类算法+机器学习人工智能+计算机毕业设计
使用Python作为开发语言,基于文本数据集(一个积极的xls文本格式和一个消极的xls文本格式文件),使用Word2vec对文本进行处理。通过支持向量机SVM算法训练情绪分类模型。实现对文本消极情感和文本积极情感的识别。并基于Django框架开发网页平台实现对用户的可视化操作和数据存储。
95 0
文本情感识别分析系统Python+SVM分类算法+机器学习人工智能+计算机毕业设计
|
7月前
|
人工智能 算法 数据可视化
DBSCAN密度聚类算法(理论+图解+python代码)
DBSCAN密度聚类算法(理论+图解+python代码)
494 0
|
7月前
|
算法 数据可视化 搜索推荐
基于python的k-means聚类分析算法,对文本、数据等进行聚类,有轮廓系数和手肘法检验
本文详细介绍了基于Python实现的k-means聚类分析算法,包括数据准备、预处理、标准化、聚类数目确定、聚类分析、降维可视化以及结果输出的完整流程,并应用该算法对文本数据进行聚类分析,展示了轮廓系数法和手肘法检验确定最佳聚类数目的方法。
176 0
|
7天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于GRU网络的MQAM调制信号检测算法matlab仿真,对比LSTM
本研究基于MATLAB 2022a,使用GRU网络对QAM调制信号进行检测。QAM是一种高效调制技术,广泛应用于现代通信系统。传统方法在复杂环境下性能下降,而GRU通过门控机制有效提取时间序列特征,实现16QAM、32QAM、64QAM、128QAM的准确检测。仿真结果显示,GRU在低SNR下表现优异,且训练速度快,参数少。核心程序包括模型预测、误检率和漏检率计算,并绘制准确率图。
80 65
基于GRU网络的MQAM调制信号检测算法matlab仿真,对比LSTM