【问题标题】:How to maintain data entry id in Mahout K-means clustering如何在 Mahout K-means 聚类中维护数据条目 ID
【发布时间】:2012-01-24 05:47:26
【问题描述】:

我正在使用 mahout 运行 k-means 聚类,但在聚类时遇到了识别数据条目的问题,例如我有 100 个数据条目

id      data
0       0.1 0.2 0.3 0.4
1       0.2 0.3 0.4 0.5
...     ...
100     0.2 0.4 0.4 0.5

聚类后,我需要从聚类结果中取回id,看看哪个点属于哪个聚类,但是id好像没有办法维护。

在mahout官方聚类合成控制数据的例子中,只有数据输入mahout,没有id like

28.7812 34.4632 31.3381 31.2834 28.9207 ...
...
24.8923 25.741  27.5532 32.8217 27.8789 ...

并且聚类结果只有cluster-id和point value:

VL-539{n=38 c=[29.950, 30.459, ...
   Weight:  Point:
   1.0: [28.974, 29.026, 31.404, 27.894, 35.985...
   2.0: [24.214, 33.150, 31.521, 31.986, 29.064

但是不存在点 ID,所以,任何人都可以知道如何在进行 mahout 集群时添加维护点 ID?非常感谢!

【问题讨论】:

    标签: apache hadoop mahout k-means


    【解决方案1】:

    您的请求经常被本身不是从业者的程序员忽略......不幸的是。我不知道 Mahout 怎么做(到目前为止),但我从 Apache-commons-math 开始,它包括一个具有相同缺陷的 K-means。我对其进行了调整,以满足您的要求。你会在这里找到它: http://code.google.com/p/noolabsimplecluster/ 另外,不要忘记将数据归一化(线性)到区间 [0..1],否则任何聚类算法都会产生垃圾!

    【讨论】:

      【解决方案2】:

      kmeans 生成的 clusteredPoints 目录包含此映射。 请注意,您应该使用 -cl 选项来获取此数据。

      【讨论】:

        【解决方案3】:

        为了实现这一点,我使用 NamedVectors。

        如您所知,在对数据进行任何聚类之前,您必须对其进行矢量化。

        这意味着您必须将数据转换为 Mahout 向量,因为那是 聚类算法使用的数据类型。

        矢量化过程将取决于数据的性质,即矢量化文本与 向量化数值。

        您的数据似乎很容易矢量化,因为它只有一个 ID 和 4 个数值。

        您可以编写一个 Hadoop 作业来获取您的输入数据,例如,作为 CSV 文件, 并输出一个序列文件,其中您的数据已经矢量化。

        然后,您将 Mahout 聚类算法应用于此输入,并将每个矢量的 ID(矢量名称)保留在聚类结果中。

        可以使用以下类实现对数据进行矢量化的示例作业:

        public class DenseVectorizationDriver extends Configured implements Tool{
        
            @Override
            public int run(String[] args) throws Exception {
                if (args.length != 2) {
                    System.err.printf("Usage: %s [generic options] <input> <output>\n", getClass().getSimpleName());
                    ToolRunner.printGenericCommandUsage(System.err); return -1;
                }
                Job job = new Job(getConf(), "Create Dense Vectors from CSV input");
                job.setJarByClass(DenseVectorizationDriver.class);
        
                FileInputFormat.addInputPath(job, new Path(args[0]));
                FileOutputFormat.setOutputPath(job, new Path(args[1]));
        
                job.setMapperClass(DenseVectorizationMapper.class);
                job.setReducerClass(DenseVectorizationReducer.class);
        
                job.setOutputKeyClass(LongWritable.class);
                job.setOutputValueClass(VectorWritable.class);
        
                job.setOutputFormatClass(SequenceFileOutputFormat.class);
        
                return job.waitForCompletion(true) ? 0 : 1;
            }
        }
        
        
        public class DenseVectorizationMapper extends Mapper<LongWritable, Text, LongWritable, VectorWritable>{
        /*
         * This mapper class takes the input from a CSV file whose fields are separated by TAB and emits
         * the same key it receives (useless in this case) and a NamedVector as value.
         * The "name" of the NamedVector is the ID of each row.
         */
            @Override
            public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        
                String line = value.toString();
                System.out.println("LINE: "+line);
                String[] lineParts = line.split("\t", -1);    
                String id = lineParts[0];
        
                //you should do some checks here to assure that this piece of data is correct
        
                Vector vector = new DenseVector(lineParts.length -1);
                for (int i = 1; i < lineParts.length -1; i++){
                    String strValue = lineParts[i];
                    System.out.println("VALUE: "+strValue);
                    vector.set(i, Double.parseDouble(strValue));
        
                }
        
                vector =  new NamedVector(vector, id);
        
                context.write(key, new VectorWritable(vector));
            }
        }
        
        
        public class DenseVectorizationReducer extends Reducer<LongWritable, VectorWritable, LongWritable, VectorWritable>{
        /*
         * This reducer simply writes the output without doing any computation.
         * Maybe it would be better to define this hadoop job without reduce phase.
         */
            @Override
            public void reduce(LongWritable key, Iterable<VectorWritable> values, Context context) throws IOException, InterruptedException{
        
                VectorWritable writeValue = values.iterator().next();
                context.write(key, writeValue);
            }
        }
        

        【讨论】:

        • 我没有看完你所有的代码,但你的第一行就足够了。 “命名向量”!
        猜你喜欢
        • 2014-05-05
        • 2017-01-26
        • 2021-12-10
        • 2013-02-07
        • 1970-01-01
        • 2012-02-05
        • 2021-09-17
        • 1970-01-01
        • 2015-04-11
        相关资源
        最近更新 更多