写个菜鸟的入门级读物:如何利用weka进行文本聚类(一)(老鸟勿进,因为你会失望的。。。)

作者:finallyliuyu(转载请注明作者和出处)

哦,(一)忘记附上了去掉字符串首尾空格的小函数了,现在补上。

 

void trim(string  &str,const string val)
{  
   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> >

...

以此类推。上个图给大家看看就一目了然了。

下面给出序列化和反序列化的代码

 

save:保存词袋子信息到硬盘
//将词典信息存到硬盘上
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();
}

 

 

load:重新加载词袋子模型到内存
void load(map<string,vector<pair<int,int> > >&mymap)
{   
    
//设置代码页为简体中文,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));

}

 

 

打印词典信息到屏幕
/打印词典信息
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;
    }
    
}

 

 下面开始介绍特征词选择模块:

首先是几个辅助函数,也就是用到泛型算法中的谓词函数

 

some assistant predicate
bool isLonger(const  pair<string,int> &pair1, const pair<string,int>  &pair2)
{
    
return pair1.second>pair2.second;
}
bool cntAssist(const  pair<string,int> &pair1)
{
    
return pair1.second<=100;
}

 

 

 

DF特征词选择方法
///关键词统计以及DF法选择特征词        
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特征词集合的函数

 

 

将特征词信息加载到内存
//获取最终选取的特征词
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出现过,以及该特征词在该篇文章中出现过几次。

 

 未完待续。。。

posted on 2010-08-30 18:52  finallyly  阅读(11731)  评论(15编辑  收藏  举报