zoukankan      html  css  js  c++  java
  • Kmeans聚类之建立词袋子模型

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

    最近打算将自己的工作平台由C#,python等迁移到C++。这是我的第一个C++工作程序吧。

    IDE:VS2008

    language: C++

    library:boost(安装boost库,先要安装python安装方法见《boost库安装方法》)

    tools:weka

    C++程序完成的功能:从数据库中读出文章-》分词(调用ICTCLAS)-》特征词选择(DF法)->VSM模型建立->把文章写成weka数据格式arff文件(此处写成的是稀疏数据的储存格式。weka教程见《教程》)

    首先给出构造停用词集合的代码:

    构造停用词表
    /************************************************************************/
    /* 获取停用词表                                                                     */
    /************************************************************************/
    set<string>MakeStopSet()
    {    
    set<string> stopwordsSet;
        ifstream ifile(
    "stopwords.txt");
        
    while(!ifile.eof())
        {
            
    string temp;
            trim(temp,
    " ");
            ifile
    >>temp;
            stopwordsSet.insert(temp);
        }
        
    return stopwordsSet;
         
        
    }

    然后我们给出调用ICTclas进行分词的代码,注意:工程中调用ICTCLAS时要把data 文件夹,config文件,ictclas30.h ICTCLAS30.dll,ICTCLAS30.LIB放在工程所在的文件夹。将ictclas30.h加入工程,在调用ICTCLAS30.DLL的cpp文件的头部加上#pragma comment(lib, "ICTCLAS30.lib")

    调用ICTCLAS分词
    ************************************************************************/
    /* c字符创形式的输入,string格式的输出,此函数用于调用ICTCLAS完成分词功能
    /*
    /***********************************************************************
    */
    string ICTsplit(const char *sInput)
    {
        
    if(!ICTCLAS_Init())
        {
            printf(
    "ICTCLAS INIT FAILED!\n");
            
    string strerr(sInput);
            
    return strerr;
        }
        ICTCLAS_SetPOSmap(ICT_POS_MAP_SECOND);
        
    //导入用户词典后
        /*printf("\n导入用户词典后:\n");
        int nCount = ICTCLAS_ImportUserDict("userdic.txt");//覆盖以前的用户词典
        //保存用户词典
        ICTCLAS_SaveTheUsrDic();
        printf("导入%d个用户词。\n", nCount);
    */

        
    const char* sResult = ICTCLAS_ParagraphProcess(sInput, 0);
        
    string strresult(sResult);
        
    //printf("%s\n", sResult);
        
    //把字符串转化成宽字符串
        wstring wsResult=myMultibyteToWideChar(strresult);
        boost::wregex wreg(L
    "\\s+");
        wsResult
    =boost::regex_replace(wsResult,wreg,wstring(L"|"));
        strresult
    =myWideCharToMultibyte(wsResult);
        

            
        
    //ofile<<str1;
        
    //ofile.close();
        
    //cout<<str1<<endl;
        
    //ICTCLAS_FileProcess("text.txt","test_result.txt",1);
        ICTCLAS_Exit();

        
    return strresult;
    }

    ICTclas分词结果默认的分割符是空格,在以上函数中,我们改成了“|”作为分隔符,字符串替换考率用boost的正则表达式库。因为我们要处理的是汉字字符串,所有要进行宽字符串窄字符串之间的转化,我采用的是利用win32函数的方法更多方法请见《boost正则表达式处理汉字字符串》。

    宽窄字符串互转函数
    /************************************************************************/
    /*  功能:将窄字符转化成宽字符,string->wstring                         */
    /************************************************************************/
    wstring myMultibyteToWideChar(
    string sResult)
    {
        
    int iWLen=MultiByteToWideChar( CP_ACP, 0, sResult.c_str(), sResult.size(), 00 );// 计算转换后宽字符串的长度。(不包含字符串结束符)
        wchar_t *lpwsz= new wchar_t [iWLen+1];
        MultiByteToWideChar( CP_ACP, 
    0, sResult.c_str(), sResult.size(), lpwsz, iWLen ); // 正式转换。
        lpwsz[iWLen] = L'\0'
        wstring wsResult(lpwsz);
        delete []lpwsz;
        
    return wsResult;
    }
    /************************************************************************/
    /* 将宽字符串转化成窄字符串用于输出                                     */
    /************************************************************************/
    string myWideCharToMultibyte(wstring wsResult)
    {    
    string sResult;
        
    int iLen= WideCharToMultiByte( CP_ACP, NULL, wsResult.c_str(), -1, NULL, 0, NULL, FALSE ); // 计算转换后字符串的长度。(包含字符串结束符)
        char *lpsz= new char[iLen];
        WideCharToMultiByte( CP_OEMCP, NULL, wsResult.c_str(), 
    -1, lpsz, iLen, NULL, FALSE); // 正式转换。
        sResult.assign( lpsz, iLen-1 ); // 对string对象进行赋值。
        delete []lpsz;
        
    return sResult;




    }

     有了以上的功能,我们现在编写一个函数,函数的输入是一篇文章,输出是一个词的集合。该词集合保存的是初步去掉噪声词后的“好词”

    代码如下

    对每篇文章初步过滤形成词集合
    /************************************************************************/
    /* 返回一篇文章中的好词                                                 */
    /************************************************************************/
    vector
    <string>goodWordsinPieceArticle(string rawtext,set<string> stopwords)
    {  
        vector
    <wstring> goodWordstemp;
        vector
    <string> goodWords;
        
    const char* sInput=rawtext.c_str();
        
    string sResult=ICTsplit(sInput);
        wstring wsResult
    =myMultibyteToWideChar(sResult);
        boost::wregex wreg(L
    "\\d+");//去掉中文空格
        wsResult=boost::regex_replace(wsResult,wreg,wstring(L""));
        
    //boost::regex_split(back_inserter(goodWordstemp),wsResult,wreg);
        boost::split(goodWordstemp,wsResult,boost::is_any_of("|"));

        
    for(vector<wstring>::iterator it=goodWordstemp.begin();it!=goodWordstemp.end();it++)
        {
            
    string temp=myWideCharToMultibyte(*it);
            trim(temp,
    " ");
            
    if(!stopwords.count(temp)&&!temp.empty())
            {
                goodWords.push_back(temp);
            }
            
        
        }

        
    return goodWords;

        
    }

     上面的这个函数可以说是我们建立词袋子模型的基本单元,给上面的函数输入文章内容(rawtext),以及停用词表,那么它将返回一个词集合。下面我们开始构造词袋子模型。在构造词袋子模型之前,我们要说一下,我们词袋子模型的格式map<string,vector<pair<int,int>>>:主键为该词,pair中的第一个int 为文章标号,第二个词为在该文中出现的次数,vector<pair<int,int>>统计的是这个词在那些文章中出现,出现过几次。因为数据量比较大所以词袋子模型map,采用引用传参,如果是值传参的话,会在内存中产生拷贝,浪费内存

    下面是从数据库中读文章建立词袋子模型的代码

    建立词袋子模型
    /************************************构建倒排表: key=word,val= a list of pairs which consists of articleid ,and count, count=tf*************************************************************/
    int ConstructMap(map<string,vector<pair<int,int>>>&mymap,int beginindex,int endindex)
    {
        
    //    vector<string> mySplit(string s);
         set<string>MakeStopSet();
        vector
    <string>goodWordsinPieceArticle(string rawtext,set<string>stopwords);
        CoInitialize(NULL);
        _ConnectionPtr pConn(__uuidof(Connection));
        _RecordsetPtr pRst(__uuidof(Recordset));
        
    char * select =new char[5000];
        memset(select,
    0,5000);
        
    char *firstpart="select CKeyWord,ArticleId,CAbstract from Article where ArticleId between ";
        
    char *lastpart=" order by ArticleId";
        
    char middlepart1[100];
        
    char middlepart2[100];
        sprintf_s(middlepart1,
    sizeof(middlepart1),"%d",beginindex);
        sprintf_s(middlepart2,
    sizeof(middlepart2),"%d",endindex);
        strcat(select,firstpart);
        strcat(select,middlepart1);
        strcat(select,
    " and ");
        strcat(select,middlepart2);
        strcat(select,lastpart);
        pConn
    ->ConnectionString="Provider=SQLOLEDB.1;Password=xxxxxx;Persist Security Info=True; User ID=sa;Initial Catalog=ArticleCollection";
        pConn
    ->Open("","","",adConnectUnspecified);
        pRst
    =pConn->Execute(select,NULL,adCmdText);
        
    set<string>stopwords=MakeStopSet();
        
    while(!pRst->rsEOF)
        {    vector
    <string>wordcollection;
            
    //string keywordstr=(_bstr_t)pRst->GetCollect("CKeyWord");
            string rawtext=(_bstr_t)pRst->GetCollect("CAbstract");
            
    if(rawtext!="")
            {
                    wordcollection
    =goodWordsinPieceArticle(rawtext,stopwords);
                    
    string tempid=(_bstr_t)pRst->GetCollect("ArticleId");
                    
    int articleid=atoi(tempid.c_str());
                    
    for(vector<string>::iterator strit=wordcollection.begin();strit!=wordcollection.end();strit++)
                    {
                        vector
    <pair<int,int>>::iterator it;
                        
    if(mymap[*strit].empty())
                        {
                            pair
    <int,int>mytemppair=make_pair(articleid,1);
                            mymap[
    *strit].push_back(mytemppair);

                        }
                        
    else
                        {
                            
    for(it=mymap[*strit].begin();it!=mymap[*strit].end();it++)
                            {  
                                
    if(it->first==articleid)
                                {
                                    it
    ->second=++(it->second);
                                    
    break;
                                }
                        
                            }
                            
    if(it==mymap[*strit].end())
                            {
                                pair
    <int,int>mytemppair=make_pair(articleid,1);
                                mymap[
    *strit].push_back(mytemppair);
                            }

                        }

                }
                

            }
            
            
            pRst
    ->MoveNext();
            wordcollection.clear();
        }
        pRst
    ->Close();
        pConn
    ->Close();
        pRst.Release();
        pConn.Release();
        CoUninitialize();
        delete[] select;
        
    return 0;

    }
    未完,待续。。。。。
  • 相关阅读:
    疫情数据背后,聊聊数据分析平台变迁史
    华为五大专家亲述:如何转型搞 AI?
    【华为云技术分享】LwM2M协议的学习与分享
    Spring5参考指南: BeanWrapper和PropertyEditor
    Spring5参考指南: Resources
    Spring5参考指南:事件Event
    Spring5参考指南:Environment
    Spring5参考指南:JSR 330标准注解
    Spring5参考指南:组件扫描
    Spring5参考指南:基于注解的容器配置
  • 原文地址:https://www.cnblogs.com/finallyliuyu/p/1812064.html
Copyright © 2011-2022 走看看