Kmeans聚类之特征词选择(DF法)

写个菜鸟的入门级读物:如何利用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出现过,以及该特征词在该篇文章中出现过几次。

 

 未完待续。。。

你可能感兴趣的:(选择)