关于聚类算法,在参与项目期间,真正用的比较多和有具体操作的是kmeans算法,因此这里就只说下mahout kmeans整体运行的IPO以及一些细节问题。
1. Kmeans算法主要需要配置的参数信息及注意事项:
①-input 输入文件,可以是一个文件或者目录,项目期间主要用了.txt .csv两种文件格式
②-output 输出目录
③-distanceMeasure 选择距离计算的方式 默认是欧氏距离平方
④-cluster 初始聚类中心点的文件路径,其包含的必须是序列文件,如果K参数被设置,则该路径上的数据将被覆盖
⑤-convergenceDelta 判断推出循环的阈值,默认是0.5,这个是用来判断准则函数时候达到阈值
⑥-maxIter 最大的循环次数
⑦-overwrite 如果出现则对输出路径进行重写
⑧-cl 是否对数据进行分类,如果出现,则会生成clusteredPoints文件
⑨-method 选择使用的计算方式,单机或者集群,默认是集群
注意事项:input 和output目录均为hdfs上的目录,其中K值可选可不选,当设置K值后,聚类中心可以不再配置。最大的聚类次数是一定要设置的,否则当聚类循环的阈值没有达到的时候就会一直循环。K值的设定可以根据经验值,用户的需要或者是通过Canopy粗聚类确定。
2.基本过程如下:
项目期间其中所使用的数据集之一为小儿中医肺炎数据,数据集的大致情况为70维属性,6000个记录,大致格式如下:(输入的源文件忘记保存了。。。)
1 0 3 2 -1 3 4
2 3 2 2 0 1 3
4 1 1 1 1-1 3
-1 3 2 0 0 0 -1
3 3 3 -1 2 0 -2
这里将源文件标记为pneumonia.txt
(1) 首先将输入文件上传到HDFS文件系统上,通过下面的命令行:
bin/hadoop fs -mkdir lyn/mahout
bin/hadoop fs -put 本地目录 lyn/mahout
(2)这里上传的文件是文本格式,
mahout下处理的文件必须是SequenceFile格式的,所以需要把txtfile转换成sequenceFile,而聚类必须是向量格式的,所以需要将其转化为向量文件
bin/mahout org.apache.mahout.clustering.conversion.InputDriver -i lyn/mahout/pneumonia.txt -o lyn/mahout/vecfile -v org.apache.mahout.math.RandomAccessSparseVector
(3)Kmeans算法运行
bin/mahout/ kmeans -i lyn/mahout/vecfile -o lyn/mahout/result -c lyn/mahout/clu -x 20 -k 3 -cd 0.1 -dm org.apache.mahout.common.distance.SquaredEuclideanDistanceMeasure -cl
(4)分析运行的结果
输出目录下有clusteredPoints、cluster-x、cluster-(x+1)-final等几个文件夹,x表示第x次迭代,每次的迭代结果都会存到cluster-x,最后一次(x+1)迭代结果存在cluster-(x+1)-final,clusteredPoints下存的也是最后聚类结果,但它俩存的东西不太一样,一个是类,一个是点。
cluster-(x+1)-final存储的格式类似下图(图源http://blog.csdn.net/dr_guo/article/details/52861328)
clusteredPoints存储的格式类似于下图,key为该点所属的类,value具体的数据对象(居然在优盘中找到当时的结果了)
kmeans生成的结果目录中的文件,直接用cat命令打开是乱码,看不到上图的内容,因为结果是序列文件,因此需要用clusterdump命令将序列文件转化为文本文件并放到本地目录中
bin/mahout clusterdump -i lyn/mahout/result/cluster-3-final -p lyn/mahout/result/clusterPoints -o 本地目录
在本地目录中就可以看到上图中的结果了
3.kmeans结果的整理
项目中因为需要对结果进行可视化展示,因此需要对结果文件进行进一步的处理, 将对应的类和点单独放到每一个文件中,具体代码如下:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test1 {
public static void main(String[] args) throws IOException {
File f = new File("e://test.txt");
System.out.println("begin");
BufferedReader bf = new BufferedReader(new FileReader(f));
String s = null;
Pattern p = Pattern.compile("(\\[)([a-z]*)(\\])");
Pattern p1 = Pattern.compile("(Key: )([\\d]{1,3})(:)(.*)(\\[)(.*)(\\])");
Pattern p2 = Pattern.compile("([\\d]{1,3})(:)(.)(.000)");
DecimalFormat df = new DecimalFormat("000");
DecimalFormat df1 = new DecimalFormat("00");
while ((s = bf.readLine()) != null) {
Matcher m = p1.matcher(s);
while (m.find()) {
String cla = df.format(Integer.parseInt(m.group(2)));
String s2 = m.group(6);
Matcher m2= p2.matcher(s2);
while(m2.find()){
System.out.println(cla+df.format(Integer.parseInt(m2.group(1)))+m2.group(3));//列名+值
}
}
}
System.out.println("end");
}
/*对聚类挖掘算法后的结果进行格式化处理
* 用来做可视化展示和关联规则的输入
* 参数 input 为要处理文件的路径
*/
static void guanlian(String input) throws IOException{
File f = new File(input);
//File out = new File(output);
BufferedReader bf = new BufferedReader(new FileReader(f));
//BufferedWriter bw = new BufferedWriter(new FileWriter(out,true));
String line = null;
int i=1;
Pattern p1 = Pattern.compile("(Key: )([\\d]{1,3})(:)(.*)(\\[)(.*)(\\])");
Pattern p2 = Pattern.compile("([\\d]+)(:)([-]?\\d)(.)");
DecimalFormat df = new DecimalFormat("00");
//DecimalFormat df1 = new DecimalFormat("00");
while((line =bf.readLine())!=null){
Matcher m = p1.matcher(line);
while(m.find()){
String s2 = m.group(6);
Matcher m1 = p2.matcher(s2);
String newline = "";
while(m1.find()){
newline += (df.format(Integer.parseInt(m1.group(1)))+m1.group(3)+' ');
}
String fileName = "e:\\guanlian\\"+m.group(2)+".txt";
System.out.println(fileName);
File f1 = new File(fileName);
if(!f1.exists())f1.createNewFile();
BufferedWriter bw = new BufferedWriter(new FileWriter(f1,true));
System.out.println(newline);
bw.write(newline);
bw.newLine();
bw.flush();
bw.close();
}
}
bf.close();
}
public static void main(String[] args) throws IOException{
guanlian("e://bat.txt");
System.out.println("complete");
}
}
处理完的结果文件和具体的内容如下:
93.txt内容如下:
至此结果基本处理完毕,下步可用于关联规则或者分类算法的输入文件。
附:将命令行写成批处理文件,利用java执行该批处理文件的过程
import java.io.*;
public class bat2 {
public void creatBat(String s) {
FileWriter fw = null;
try {
String str="/mahout/mahout-distribution-0.9/p.txt";
String[] strarray=str.split("/");
String strfilename=strarray[strarray.length-1];
String strpath="/user/hadoop/mahout6/"+strfilename;
String strclass="20";
Integer kind=Integer.parseInt(strclass);
fw = new FileWriter(s);
fw.write("hadoop fs -rmr /user/hadoop/mahout6"+ "\n");
fw.write("hadoop fs -mkdir -p /user/hadoop/mahout6"+ "\n");
fw.write("hadoop fs -put "+str+" /user/hadoop/mahout6"+"\n");
fw.write("mahout org.apache.mahout.clustering.conversion.InputDriver -i "+strpath+" -o /user/hadoop/mahout6/vecfile -v org.apache.mahout.math.RandomAccessSparseVector"+"\n");
fw.write("mahout kmeans -i /user/hadoop/mahout6/vecfile -o /user/hadoop/mahout6/result1 -c /user/hadoop/mahout6/clu1 -x "+kind+" -k 3 -cd 0.1 -dm org.apache.mahout.common.distance.SquaredEuclideanDistanceMeasure -cl"+"\n");
fw.write("mahout seqdumper -i /user/hadoop/mahout6/result1/clusteredPoints/part-m-00000 -o /mahout/test/bat.txt");
} catch (IOException e) {
e.printStackTrace();
System.exit(0);
} finally {
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(0);
}
}
}
}
private String execute(String batname) {
File file = new File(batname);
if (file.exists()){
file.setExecutable(true);
file.setReadable(true);
file.setWritable(true);
}else{
System.out.println("File no exists.");
}
Process process;
String line = null;
StringBuffer sb = new StringBuffer();
try {
process = Runtime.getRuntime().exec(batname);
InputStream fis = process.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
while ((line = br.readLine()) != null) {
System.out.println(line);
}
if (process.waitFor() != 0) {
System.out.println("fail");
return "fail";
}
System.out.println(batname + " run successful!");
return "success";
} catch (Exception e) {
e.printStackTrace();
return "fail";
}
}
public static void main(String[] args) {
String batname="del.sh";
File file = new File(batname);
if(file.exists())
file.delete();
bat2 df = new bat2();
System.out.println(file.getAbsolutePath());
df.creatBat(file.getAbsolutePath());
df.execute(file.getAbsolutePath());
}
}