写个菜鸟的入门级读物:如何利用weka进行文本聚类(一)(老鸟勿进,因为你会失望的。。。)
作者:finallyliuyu(转载请注明作者和出处)
哦,(一)忘记附上了去掉字符串首尾空格的小函数了,现在补上。
{
str.erase( 0 ,str.find_first_not_of(val));
str.erase(str.find_last_not_of(val) + val.size());
}
在(一)中,我们已经建立了稳定词袋子模型,这个词袋子模型可是个宝贝家伙,我们一定要小心维护。为什么呢?因为 特征词选择模块,VSM(文档向量模型)的建立模块,我们都要用到它。另外我们也说了这个这个东西很占内存,所以我们不能在特征词选择的时候调用一次这个函数,然后在建立VSM模型的时候再调用一次这个函数,这样会影响程序的运行速度,所以最好的方法就是把这个宝贝家伙保存到硬盘上。序列化。对于序列化这个复杂的map,我问过嗷嗷,也问过同学,有人建议我用boost库,但是我觉得最简单的方法还是自己按某种规则自己序列化到硬盘,然后解序列化到内存。
至于格式,我是这么定义的。
首行,词的总个数
然后
词1的text
词1的DF,
然后是vector<pair<int,int> >
...
以此类推。上个图给大家看看就一目了然了。
下面给出序列化和反序列化的代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
void save(map < string ,vector < pair < int , int > > >& mymap)
{ ofstream outfile( " f:\\mydict.dat " ,ios::binary);
outfile << mymap.size() << endl;
map < string ,vector < pair < int , int > > > ::iterator it;
for (it = mymap.begin();it != mymap.end();it ++ )
{ outfile << it -> first << endl;
vector < pair < int , int >> ::iterator subit;
outfile << it -> second.size() << endl;
for (subit = (it -> second).begin();subit != (it -> second).end(); ++ subit)
{
outfile << subit -> first << " " << subit -> second << " " << " ; " << " " ;
}
outfile << endl;
}
// outfile.write((char *)&mymap,sizeof(mymap));
outfile.close();
}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{
// 设置代码页为简体中文,936是简体中文的代码页。
std::locale loc1 = std::locale:: global (std::locale( " .936 " ));
{
// 在这里使用std::ifstream 或者 std::fstream
ifstream infile( " F:\\mydict.dat " ,ios::binary);
int lenMyMap; // 保存词典长度
int lenVector; // 保存每个词出现的文章数目
string key; // 保存读出的map的键值
int articleId; // 文章标号
int count; // 在该文章中刚出现的数目
string comma;
string semicolon;
infile >> lenMyMap;
while ( ! infile.eof())
{
infile >> key;
infile >> lenVector;
vector < pair < int , int > > temp;
for ( int i = 0 ;i < lenVector;i ++ )
{
infile >> articleId >> count >> semicolon;
temp.push_back(make_pair(articleId,count));
}
mymap[key] = temp;
}
infile.close();
}
std::locale:: global (std::locale(loc1));
}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
void print(map < string ,vector < pair < int , int > > >& mymap)
{
cout << mymap.size() << endl;
map < string ,vector < pair < int , int > > > ::iterator it;
for (it = mymap.begin();it != mymap.end();it ++ )
{ cout << it -> first << endl;
vector < pair < int , int >> ::iterator subit;
cout << it -> second.size() << endl;
for (subit = (it -> second).begin();subit != (it -> second).end(); ++ subit)
{
cout << subit -> first << ' , ' << subit -> second << " ; " ;
}
cout << endl;
}
}
下面开始介绍特征词选择模块:
首先是几个辅助函数,也就是用到泛型算法中的谓词函数
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{
return pair1.second > pair2.second;
}
bool cntAssist( const pair < string , int > & pair1)
{
return pair1.second <= 100 ;
}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
void DFcharicteristicWordSelection(map < string ,vector < pair < int , int >>> & mymap, int DFthreshold)
{ int finalKeyWordsCount = 0 ; // 计算共取了多少个关键词
vector < pair < string , int > > tempvector;
for (map < string ,vector < pair < int , int >>> ::iterator it = mymap.begin();it != mymap.end(); ++ it)
{
tempvector.push_back(make_pair(it -> first,(it -> second).size()));
}
stable_sort(tempvector.begin(),tempvector.end(),isLonger);
ofstream outfile( " F:\\keywordsinfo.txt " );
for (vector < pair < string , int > > ::iterator it = tempvector.begin();it != tempvector.end();it ++ )
{
if (it -> second >= DFthreshold)
{
// outfile<<it->first<<" "<<it->second<<endl;
outfile << it -> first << endl;
finalKeyWordsCount ++ ;
}
}
outfile.close();
cout << " 最后共选择特征词 " << finalKeyWordsCount << endl;
cout << " by the way,DFthreshold equals " << DFthreshold << endl;
}
下面给出特征词文件的部分截图
有一点要提醒大家哈,特征词选择模块执行之前,要load 词袋子模型到内存哈。
下面我们开始给出建立VSM模型的代码。
建立VSM模型需要两个数据,词袋子就是前面所说的那个map,以及刚刚选出的特征词。load map的函数已经给出,下面给出load特征词集合的函数
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
vector < string > GetFinalKeyWords()
{
vector < string > myKeys;
ifstream infile( " F:\\keywordsinfo.txt " );
while ( ! infile.eof())
{
string temp;
infile >> temp;
if (temp != "" )
{
myKeys.push_back(temp);
}
}
return myKeys;
}
方法就是:对于每一篇文章,检查我们选出的特征词集合,对于每个特征词,查map,看看里面有没有该篇文章的id出现过,以及该特征词在该篇文章中出现过几次。
未完待续。。。