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