随机计算TFIDF作为权重,然后利用余弦距离进行聚类,用的是简单k-means算法。

来源:互联网 发布:怎么取消淘宝卖家的钻 编辑:程序博客网 时间:2024/06/07 03:45

#include <iostream>

#include <string>#include <vector>#include <map>#include <utility>#include <sstream>#include <cmath>#include <cstdlib>#include <ctime>using namespace std;struct Kmeans{    vector< pair<string,map<string,int>> > asAllLines;    //存储所有文本行以及每一行各个单词出现次数,用于计算TF    vector< vector<double> > aaLinesTf;    //所有文本行对应所有单词的TF*IDF    map<string,int> mKeyAprLines;    //每个单词在多少行里出现过,用于计算IDF    vector< vector<double> > aCluCenter;    //聚类中心     vector<int> aiLinesInCenter;    //每个中心聚集了多少文本行    vector<int> aLinesCenter;    //每个文本行属于哪个聚类中心    int iKeyNum;    //单词种类    int iLineNum;    //总文本行数    int iCenterNum;    //中心个数};#define MAX_DISTANCE 1e6void stringToLower(string &key){    for(int i=0;i<(int)key.size();)    {        if(key[i]<0)        {            i+=2;        }        else         {            if('A'<=key[i] && key[i]<='Z')            {                key[i]=key[i]-'A'+'a';            }            i++;        }    }}void kMeansCentersRandomInit(Kmeans *pKmeans){    srand((unsigned int)time(NULL));    for(int i=0;i<pKmeans->iCenterNum;++i)    {        bool bContinue=true;        do        {            int iToSelect=rand()%pKmeans->iLineNum;            if(pKmeans->aLinesCenter[iToSelect]==-1)            {                for(int j=0;j<pKmeans->iKeyNum;++j)                {                    pKmeans->aCluCenter[i][j]=pKmeans->aaLinesTf[iToSelect][j];                }                pKmeans->aLinesCenter[iToSelect]=i;                cout<<"初始化中心"<<i<<":"<<pKmeans->asAllLines[iToSelect].first<<endl;                bContinue=false;            }        }while(bContinue);    }}int kMeansInit(Kmeans *pKmeans,const vector<string> &asAllLines,int iLineNum,int iCenterNum){    if(pKmeans==NULL)    {        return -1;    }    pKmeans->asAllLines.assign(iLineNum,pair< string,map<string,int> >());    pKmeans->aaLinesTf.assign(iLineNum,vector<double>());    pKmeans->aCluCenter.assign(iCenterNum,vector<double>());    pKmeans->aiLinesInCenter.assign(iCenterNum,0);    pKmeans->aLinesCenter.assign(iLineNum,0);    pKmeans->iLineNum=iLineNum;    pKmeans->iCenterNum=iCenterNum;    //拆分单词,统计数据    for(int i=0;i<(int)asAllLines.size();++i)    {        pKmeans->asAllLines[i].first=asAllLines[i];        istringstream istrm(asAllLines[i]);        string key;        while(istrm>>key)        {            stringToLower(key);            if(pKmeans->asAllLines[i].second.find(key)==pKmeans->asAllLines[i].second.end())            {                pKmeans->asAllLines[i].second[key]=1;            }            else            {                pKmeans->asAllLines[i].second[key]++;            }            if(pKmeans->asAllLines[i].second[key]==1)            {                pKmeans->mKeyAprLines[key]++;            }        }    }    pKmeans->iKeyNum=pKmeans->mKeyAprLines.size();        for(int i=0;i<pKmeans->iLineNum;++i)    {        pKmeans->aaLinesTf[i].assign(pKmeans->iKeyNum,0);        pKmeans->aLinesCenter[i]=-1;    }    for(int i=0;i<pKmeans->iCenterNum;++i)    {        pKmeans->aCluCenter[i].assign(pKmeans->iKeyNum,0);    }        //计算TF-IDF    int iKeyIndex=0;    for(map<string,int>::iterator iter=pKmeans->mKeyAprLines.begin();iter!=pKmeans->mKeyAprLines.end();++iter,++iKeyIndex)    {        for(int line=0;line<iLineNum;++line)        {            if(pKmeans->asAllLines[line].second.find(iter->first)==pKmeans->asAllLines[line].second.end())            {                pKmeans->aaLinesTf[line][iKeyIndex]=0;                }            else            {                double TF=1.0*pKmeans->asAllLines[line].second[iter->first]/pKmeans->asAllLines[line].second.size();                double DF=log(1.0*pKmeans->iLineNum/iter->second);                pKmeans->aaLinesTf[line][iKeyIndex]=TF*DF;            }        }    }    return 0;}void kMeansMainLoop(Kmeans *pKmeans,int iTimes,double iThreshold){    /*    if(iTimes==0 && iThreshold==0)    {        return;    //没有终止条件    }    */    int iLeftTimes=iTimes;    double lastJ=-1;    vector<int> aPreLinesCenter;    //之前的聚类    kMeansCentersRandomInit(pKmeans);    while(true)    {        double J=0;        pKmeans->aiLinesInCenter.assign(pKmeans->iCenterNum,0);        aPreLinesCenter=pKmeans->aLinesCenter;    //保存之前的聚类        //聚类        for(int i=0;i<pKmeans->iLineNum;++i)        {            int iCtrIndex=-1;            double minDist=MAX_DISTANCE;                        for(int j=0;j<pKmeans->iCenterNum;++j)            {                double dist,centerSum=0,lineSum=0,crossSum=0;                for(int k=0;k<pKmeans->iKeyNum;++k)                {                    crossSum+=pKmeans->aaLinesTf[i][k]*pKmeans->aCluCenter[j][k];                    centerSum+=pKmeans->aCluCenter[j][k]*pKmeans->aCluCenter[j][k];                    lineSum+=pKmeans->aaLinesTf[i][k]*pKmeans->aaLinesTf[i][k];                }                dist=crossSum/(sqrt(centerSum)*sqrt(lineSum));                dist=1-dist;                                if(dist<minDist)                {                    iCtrIndex=j;                    minDist=dist;                }            }            pKmeans->aLinesCenter[i]=iCtrIndex;            pKmeans->aiLinesInCenter[iCtrIndex]++;            J+=minDist*minDist;        }        int iCnt=0;        for(int i=0;i<pKmeans->iLineNum;++i)        {            if(pKmeans->aLinesCenter[i]==aPreLinesCenter[i])            {                iCnt++;            }        }        if(iCnt==pKmeans->iLineNum)        {            break;        }        //重新计算各聚类中心点        for(int i=0;i<pKmeans->iCenterNum;++i)        {            for(int j=0;j<pKmeans->iKeyNum;++j)            {                pKmeans->aCluCenter[i][j]=0;            }        }        for(int i=0;i<pKmeans->iLineNum;++i)        {            for(int j=0;j<pKmeans->iKeyNum;++j)            {                pKmeans->aCluCenter[pKmeans->aLinesCenter[i]][j]+=pKmeans->aaLinesTf[i][j];            }        }        //求均值,更新聚类中心        for(int i=0;i<pKmeans->iCenterNum;++i)        {            if(pKmeans->aLinesCenter[i]!=0)            {                for(int j=0;j<pKmeans->iKeyNum;++j)                {                        pKmeans->aCluCenter[i][j]/=pKmeans->aiLinesInCenter[i];                }            }        }        if(iTimes!=0 && --iLeftTimes==0)        {            break;        }        if(iThreshold!=0 && lastJ!=-1 && fabs(lastJ-J)<iThreshold)        {            break;        }        lastJ=J;    }}int main(){    Kmeans test;    string input[]=    {        "奥运 拳击 入场券 基本 分罄 邹市明 夺冠 对手 浮出 水面",        "股民 要 清楚 自己 的 目的",        "印花税 之 股民 四季",        "杭州 股民 放 鞭炮 庆祝 印花税 下调",        "残疾 女 青年 入围 奥运 游泳 比赛 创 奥运 历史 两 项 第一",        "介绍 一 个 ASP.net MVC 系列 教程",        "在 asp.net 中 实现 观察者 模式 ,或 有 更 好 的 方法 (续)",        "输 大钱 的 股民 给 我们 启迪",        "Asp.Net 页面 执行 流程 分析",        "运动员 行李 将 “后 上 先 下” 奥运 相关 人员 行李 实名制",        "asp.net 控件 开发 显示 控件 内容",        "奥运 票务 网上 成功 订票 后 应 及时 到 银行 代售 网点 付款",        "某 心理 健康 站 开张 后 首 个 咨询 者 是 位 新 股民",        "ASP.NET 自定义 控件 复杂 属性 声明 持久性 浅析"    };/*    for(int i=0;i<14;++i)    {        stringToLower(input[i]);        cout<<input[i]<<endl;    }*/    vector<string> allLines(input,input+sizeof(input)/sizeof(string));    kMeansInit(&test,allLines,sizeof(input)/sizeof(string),3);    kMeansMainLoop(&test,0,0);    for(int i=0;i<test.iCenterNum;++i)    {        cout<<"Center "<<i<<" : "<<endl;        for(int j=0;j<test.iLineNum;++j)        {            if(test.aLinesCenter[j]==i)            {                cout<<test.asAllLines[j].first<<endl;            }        }        cout<<endl;    }    return 0;}
http://topic.csdn.net/u/20110906/11/89e01a81-923d-4cfb-b0ed-3dd295c1fd98.html

初始化

原创粉丝点击