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