#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 1e6 void 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
初始化