微信搜索lxw1234bigdata | 邀请体验:数阅–数据管理、OLAP分析与可视化平台 | 赞助作者:赞助作者

Mahout使用K-Means进行中文文本聚类

数据仓库/数据库 lxw1234@qq.com 13327℃ 4评论

关键词:Mahout、K-Means、中文聚类

一、数据准备

版本说明

使用的Mahout版本为apache-mahout-distribution-0.10.1

使用的Hadoop版本为hadoop-2.3.0-cdh5.0.0

分词

使用爬虫对每个URL的标题、关键词、描述进行爬取,再用中文分词工具进行分词;

(中文分词工具:http://lxw1234.com/archives/2015/07/422.htm

最后,每个URL的分词结果生成一个文本文件,以空格分隔,如:

url1.txt
四驱 旗舰版 多媒体 配置 参数 明细  
url2.txt
代表 四宝 厨艺 视频 烹饪 四宝 如意 金砖 富贵 骑士 视频  
url3.txt
体验 泰国 之旅 曼谷 高尔夫球场 球场 腾讯网 体验 泰国 之旅 曼谷 高尔夫球场 球场  
……

将文本文件转换成SequenceFile

将前面分词后的*.txt压缩上传至Hadoop网关机,解压到一个本地目录,如/tmp/txt/

使用Mahout命令将文本文件转换成SequenceFile,同时会将这么多小文本文件合并成一个Sequence:

cd $MAHOUT_HOME/bin
export MAHOUT_LOCAL=true
./mahout seqdirectory -i file:///tmp/txt/ -o file:///home/lxw1234/txt-seq/ -c UTF-8 -chunk 64 -xm sequential

参数说明:

MAHOUT_LOCAL:指定Mahout是否以本地模式运行;如果该变量值为空,则表示在Hadoop上运行;

seqdirectory:Mahout自带的将文本文件转换成SequenceFile的命令;

-i:输入的文本文件目录;

-o:输出的SequenceFile目录;

-xm sequential:表示在本地执行,而不是用MapReduce执行;

-c UTF8:使用UTF8编码格式;

-chunk 64:64M一个chunk,也就是文件块block,应该和HDFS的块大小一致或成倍数关系;

执行成功后,在本地的/home/lxw1234/txt-seq/目录下生成了chunk-0文件,该文件格式为SequenceFile,可以用hadoop fs –text命令查看文件内容:

hadoop fs -text file:///home/lxw1234/txt-seq/chunk-0 | more
/url809.txt         哈弗 精英 网易 精英 图片 哈弗 精英 哈弗 精英 车厢 内饰 哈弗 精英 细节 图片 哈弗 精英 经销商 图片  

/url1369.txt        内饰 基本 不变 凤凰网 内饰 基本 不变  

/url2625.txt        浪琴 按钮 致敬 历史 传统  

/url2267.txt        一汽 马自达 阿特 少量  

/url1831.txt        广州 的哥 收入 减半 租车公司 广州 的哥 收入 广州 的哥 离职 广州  

将文本文件转换成SequenceFile也可以自己写程序来完成,Mahout也提供了相应的API。

将转换好的SequenceFile上传至HDFS

hadoop fs -mkdir /tmp/mahout/txt-seq/

hadoop fs -put /home/lxw1234/txt-seq/chunk-0 /tmp/mahout/txt-seq/

将SequenceFile上传至HDFS的/tmp/mahout/txt-seq/目录

 

二、解析SequenceFile,转换成向量表示

Mahout聚类算法使用向量空间(Vectors)作为数据数据。

接下来在Hadoop上,使用之前生成的SequenceFile,转换成向量表示:

使用命令:

cd $MAHOUT_HOME/bin
export MAHOUT_LOCAL=
export HADOOP_CLASSPATH=/home/lxw1234/apache-mahout-distribution-0.10.1/lib/lucene-analyzers-common-4.6.1.jar:
				/home/lxw1234/apache-mahout-distribution-0.10.1/lib/lucene-core-4.6.1.jar:$HADOOP_CLASSPATH
./mahout seq2sparse -i /tmp/mahout/txt-seq/ -o /tmp/mahout/txt-sparse -ow \
	--weight tfidf --maxDFPercent 90 --namedVector \
	-a org.apache.lucene.analysis.core.WhitespaceAnalyzer

参数说明:

MAHOUT_LOCAL:由于要在Hadoop上完成转换,因此,设该变量值为空;

HADOOP_CLASSPATH:加入需要的jar包到Hadoop的classpath,这两个jar包主要是mahout用来分词的;

seq2sparse:Mahout自带的解析向量的命令;

-i:输入的SequenceFile目录;

-o:输出目录;

-ow:当输出目录存在时,覆盖;

–weight tfidf:权重公式,可选的有tfidf和tf;

–maxDFPercent:过滤高频词,当DF值大于90%时候,将会被过滤掉;

–namedVector:生成的向量同时输出附加信息;

-a:指定分词器;由于Mahout本身对中文支持不好,前面已经将中文做好了分词,以空格分隔,这里指定的WhitespaceAnalyzer是以空格为分隔符的分词器;

 

其他可能有用的选项:

–minDF:最小DF阈值;

–minSupport:最小的支持度阈值,默认为2;

–maxNGramSize:是否创建ngram,默认为1。建议一般设定到2就够了;

–minLLR:The minimum Log Likelihood Ratio。默认为1.0。当设定了-ng > 1后,建议设置为较大的值,只过滤有意义的N-Gram。

–logNormalize:是否对输出向量做Log变换;

其他可输入命令./mahout seq2sparse –help 来查看。

 

在HDFS上查看解析后的结果:

hadoop fs -ls /tmp/mahout/txt-sparse
Found 7 items
/tmp/mahout/txt-sparse/df-count
/tmp/mahout/txt-sparse/dictionary.file-0
/tmp/mahout/txt-sparse/frequency.file-0
/tmp/mahout/txt-sparse/tf-vectors
/tmp/mahout/txt-sparse/tfidf-vectors
/tmp/mahout/txt-sparse/tokenized-documents
/tmp/mahout/txt-sparse/wordcount

各个文件的用途:

  • file-0:文件。词文本 -> 词id(int)的映射。词转化为id,这是常见做法。
hadoop fs -text /tmp/mahout/txt-sparse/dictionary.file-0 | more
一发不可收拾    0
万元    1
两种    2
书店    3
书画    4
以上    5
低于    6
偷窥    7
全部    8
写真    9
前排    10

 

  • df-count:目录。词id->文档频率(df);
hadoop fs -text /tmp/mahout/txt-sparse/df-count/* | more
0       1
15      2
30      4
45      7
60      2
75      1
90      6
105     1
120     5
135     1
150     2
165     2
180     2

 

  • file:词id -> 文档集词频(cf)。
hadoop fs -text /tmp/mahout/txt-sparse/frequency.file-0 | more
0       1
15      2
30      4
45      7
60      2
75      1
90      6
105     1
120     5
135     1
150     2
165     2
180     2
195     470

 

  • wordcount:目录。词文本 -> 文档集词频(cf),这个应该是各种过滤处理之前的信息。
hadoop fs -text /tmp/mahout/txt-sparse/wordcount/* | more
一发不可收拾    2
万元    220
两种    2
书店    2
书画    2
以上    2
低于    2
偷窥    3
全部    2
写真    3
前排    11

 

  • tf-vectors、tfidf-vectors:目录。词向量,每篇文档一行,格式为{词id:特征值},其中特征值为tf或tfidf。采用了内置类型VectorWritable,需要用命令”mahout vectordump -i <path>”查看。
./mahout vectordump -i /tmp/mahout/txt-sparse/tf-vectors/ | more
{346:1.0,208:1.0,1532:1.0,668:1.0,238:1.0}
{390:2.0,367:1.0,844:2.0,692:2.0,952:1.0}
{1070:1.0}
{896:1.0,1341:1.0,434:1.0,153:6.0,195:1.0,838:1.0,1005:1.0,739:3.0,1025:1.0,1480:6.0,707:6.0}
{896:1.0,1341:1.0,838:1.0,153:6.0,195:1.0,1480:6.0,739:3.0,707:6.0}
{896:1.0,1341:1.0,838:1.0,153:6.0,195:1.0,1480:6.0,1005:1.0,739:3.0,707:6.0}

./mahout vectordump -i /tmp/mahout/txt-sparse/tfidf-vectors/ | more
{346:5.210176467895508,208:4.858778476715088,1532:7.749150276184082,668:6.545177459716797,238:6.075173854827881}
{390:7.129191875457764,367:7.749150276184082,844:11.532367706298828,692:11.532367706298828,952:7.749150276184082}
{1070:7.749150276184082}
{896:3.622015953063965,1341:2.697159767150879,434:7.2383246421813965,153:16.578933715820312,195:2.692904472351074,838:2.680246114730835,1005:3.03
6621570587158,739:4.602833271026611,1025:7.2383246421813965,1480:16.578933715820312,707:10.790275573730469}
{896:3.622015953063965,1341:2.697159767150879,838:2.680246114730835,153:16.578933715820312,195:2.692904472351074,1480:16.578933715820312,739:4.60
2833271026611,707:10.790275573730469}

 

  • tokenized-documents:分词后的文档。

 

三、运行K-Means

cd $MAHOUT_HOME/bin
export MAHOUT_LOCAL=
./mahout kmeans -i /tmp/mahout/txt-sparse/tfidf-vectors -c /tmp/mahout/txt-kmeans-clusters \
	-o /tmp/mahout/txt-kmeans -k 30  \
	-dm org.apache.mahout.common.distance.CosineDistanceMeasure -x 300 -ow --clustering 

参数说明:

-i:输入为上面产出的tfidf向量。

-o:每一轮迭代的结果将输出在这里。

-k:几个簇,即最终聚为几个类别。

-c:若不设定k,则用这个目录里面的点,作为聚类中心点。否则,随机选择k个点,作为中心点。

-dm:距离公式,文本类型推荐用cosine距离。

-x:最大迭代次数。

–clustering:在mapreduce模式运行。

–convergenceDelta:迭代收敛阈值,默认0.5,对于Cosine来说略大。

输出1,初始随机选择的中心点;

hadoop fs -ls /tmp/mahout/txt-kmeans-clusters

Found 1 items

/tmp/mahout/txt-kmeans-clusters/part-randomSeed

 

输出2,聚类过程、结果:

hadoop fs -ls /tmp/mahout/txt-kmeans

Found 5 items

/tmp/mahout/txt-kmeans/_policy

/tmp/mahout/txt-kmeans/clusteredPoints

/tmp/mahout/txt-kmeans/clusters-0

/tmp/mahout/txt-kmeans/clusters-1

/tmp/mahout/txt-kmeans/clusters-2-final

 

其中,clusters-k(-final)为每次迭代后,簇的30个中心点的信息。

四、查看聚类结果

由于Mahout的clusterdump命令只能在本地运行,因此需要将聚类结果从HDFS下载到本地:

hadoop fs -get /tmp/mahout/txt-kmeans/ /home/lxw1234/

hadoop fs -get /tmp/mahout/txt-sparse/ /home/lxw1234/

运行命令:

cd $MAHOUT_HOME/bin
export MAHOUT_LOCAL=true
./mahout clusterdump -i /home/lxw1234/txt-kmeans/clusters-2-final \
	-d /home/lxw1234/txt-sparse/dictionary.file-0 -dt sequencefile \
	-o /home/lxw1234/txt-kmeans-cluster-dump -n 50

参数说明:

-i:输入最终迭代生成的簇结果。

-d:使用 词 -> 词id 映射,使得我们输出结果中,可以直接显示每个簇,权重最高的词文本,而不是词id。

-dt:上面映射类型。

-o:最终产出目录。

-n:每个簇,只输出50个权重最高的词。

 

看看dump出来的结果:

mahout kmeans

出来的聚类结果有些还可以,有些看上去有点不靠谱。

对Mahout的很多参数理解不够,还有待调整。

中文分词也是影响结果的重要因素。

本文只做测试性的试验。

 

如果觉得本博客对您有帮助,请 赞助作者

转载请注明:lxw的大数据田地 » Mahout使用K-Means进行中文文本聚类

喜欢 (12)
分享 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(4)个小伙伴在吐槽
  1. 请教下为什么我输入hadoop fs -text没有反应呢 [hanlei@hadoop01 bin]$ hadoop fs -text /mahout/txt-sparse/dictionary.file-0 | more [hanlei@hadoop01 bin]$
    磊磊2016-09-23 10:39 回复
  2. ./mahout kmeans初始聚类中心怎么指定呢?
    小米饭2017-03-01 16:21 回复
  3. 您好,我照着您的文档,由序列文件转换成向量文件,tf-vectors文件打开没有内容,而除它之外的文件都没问题,这是为什么?
    王贺2017-05-09 16:40 回复
  4. No input clusters found in /k-means/input/kmeansparse-kmeans-clusters/part-randomSeed. Check your -c argument. 为什么我的老提示这个错误,在前面明明有写的记录:18/04/11 10:14:28 INFO kmeans.RandomSeedGenerator: Wrote 20 Klusters to /k-means/input/kmeansparse-kmeans-clusters/part-randomSeed
    bravo2018-04-11 22:17 回复