5

我正在用 Mahout 分析 k-means 算法。我将运行一些测试,观察性能,并对我得到的结果进行一些统计。

我不知道如何在 Mahout 中运行我自己的程序。但是,命令行界面可能就足够了。

要运行我做的示例程序

$ mahout seqdirectory --input uscensus --output uscensus-seq
$ mahout seq2sparse -i uscensus-seq -o uscensus-vec
$ mahout kmeans -i reuters-vec/tfidf-vectors -o uscensus-kmeans-clusters -c uscensus-kmeans-centroids -dm org.apache.mahout.common.distance.CosineDistanceMeasure -x 5 -ow -cl -k 25

数据集是一个大型 CSV 文件。每一行都是一条记录。特征以逗号分隔。第一个字段是 ID。由于输入格式,我不能立即使用 seqdirectory。我正在尝试实现这个类似问题的答案How to perform k-means clustering in mahout with vector data stored as CSV? 但我还有 2 个问题:

  1. 如何从 CSV 转换为 SeqFile?我想我可以使用 Mahout 编写自己的程序来进行这种转换,然后将其输出用作 seq2parse 的输入。我想我可以使用 CSVIterator ( https://cwiki.apache.org/confluence/display/MAHOUT/File+Format+Integrations )。我应该使用什么类来阅读和写作?
  2. 如何构建和运行我的新程序?我无法通过 Mahout 这本书或这里的其他问题来解决这个问题。
4

5 回答 5

5

要以 SequenceFile 格式获取数据,您可以采取一些策略。两者都涉及编写您自己的代码——即,不是严格的命令行。

策略 1 使用 Mahout 的 CSVVectorIterator 类。你传给它一个 java.io.Reader,它会读入你的 CSV 文件,把每一行变成一个 DenseVector。我从未使用过它,但在 API 中看到了它。如果您对 DenseVectors 没问题,看起来就足够直截了当。

策略 2 编写自己的解析器。这真的很简单,因为您只需在“,”上分割每一行,并且您有一个可以循环的数组。对于每行中的每个值数组,您可以使用如下方式实例化一个向量:

new DenseVector(<your array here>);

并将其添加到列表中(例如)。

然后......一旦你有一个向量列表,你可以使用这样的东西将它们写入 SequenceFiles(我在下面的代码中使用 NamedVectors):

FileSystem fs = null;
SequenceFile.Writer writer;
Configuration conf = new Configuration();

List<NamedVector> vectors = <here's your List of vectors obtained from CSVVectorIterator>;

// Write the data to SequenceFile
try {
    fs = FileSystem.get(conf);

    Path path = new Path(<your path> + <your filename>);
    writer = new SequenceFile.Writer(fs, conf, path, Text.class, VectorWritable.class);

    VectorWritable vec = new VectorWritable();
    for (NamedVector vector : dataVector) {

        vec.set(vector);
        writer.append(new Text(vector.getName()), vec);

    }
    writer.close();

} catch (Exception e) {
    System.out.println("ERROR: "+e);
}

现在,您有了一个 SequenceFile 格式的“点”目录,可用于 K-means 聚类。您可以将命令行 Mahout 命令指向此目录作为输入。

无论如何,这是一般的想法。可能还有其他方法。

于 2013-02-21T13:20:46.907 回答
3

要使用 csv 文件运行 kmeans,首先您必须创建一个 SequenceFile 以作为 KmeansDriver 中的参数传递。以下代码读取CSV文件“points.csv”的每一行并将其转换为向量并将其写入SequenceFile“points.seq”

try (
            BufferedReader reader = new BufferedReader(new FileReader("testdata2/points.csv"));
            SequenceFile.Writer writer = new SequenceFile.Writer(fs, conf,new Path("testdata2/points.seq"), LongWritable.class, VectorWritable.class)
        ) {
            String line;
            long counter = 0;
            while ((line = reader.readLine()) != null) {
                String[] c = line.split(",");
                if(c.length>1){
                    double[] d = new double[c.length];
                    for (int i = 0; i < c.length; i++)
                            d[i] = Double.parseDouble(c[i]);
                    Vector vec = new RandomAccessSparseVector(c.length);
                    vec.assign(d);

                VectorWritable writable = new VectorWritable();
                writable.set(vec);
                writer.append(new LongWritable(counter++), writable);
            }
        }
        writer.close();
    }

希望能帮助到你!!

于 2013-08-01T08:15:45.183 回答
1

当我运行上述代码时出现了一些问题,因此对语法进行了一些修改,这里是工作代码。

String inputfiledata = Input_file_path;
            String outputfile = output_path_for_sequence_file;
            FileSystem fs = null;
            SequenceFile.Writer writer;
            Configuration conf = new Configuration();
            fs = FileSystem.get(conf);
            Path path = new Path(outputfile);`enter code here`
            writer = new SequenceFile.Writer(fs, conf, path, Text.class, VectorWritable.class);
            VectorWritable vec = new VectorWritable();
            List<NamedVector> vects = new ArrayList<NamedVector>();
            try {
                fr = new FileReader(inputfiledata);
                br = new BufferedReader(fr);
                s = null;
                while((s=br.readLine())!=null){

                    // My columns are split by tabs with each entry in a new line as rows
                    String spl[] = s.split("\\t");
                    String key = spl[0];
                    Integer val = 0;
                    for(int k=1;k<spl.length;k++){
                                colvalues[val] = Double.parseDouble(spl[k]);
                                val++;
                        }
                    }
                    NamedVector nmv = new NamedVector(new DenseVector(colvalues),key);
                    vec.set(nmv);
                    writer.append(new Text(nmv.getName()), vec);
                }
                            writer.close();

            } catch (Exception e) {
                System.out.println("ERROR: "+e);
            }
        }
于 2013-03-26T22:04:26.837 回答
0

我建议您实现一个程序,将 CSV 转换为 mahout 接受的稀疏矢量序列文件。
您需要做的是了解 InputDriver 如何将包含以空格分隔的浮点数的文本文件转换为 VectorWritable 的 Mahout 序列文件,特别适用于集群作业的输入,以及通常需要此输入的任何 Mahout 作业。您将根据需要自定义代码。
如果您已经下载了 Mahout 的源代码,那么 InputDriver 位于包 org.apache.mahout.clustering.conversion。

于 2013-01-25T04:10:05.633 回答
0

org.apache.mahout.clustering.conversion.InputDriver 是一个可以用来创建稀疏向量的类。

示例代码如下

mahout org.apache.mahout.clustering.conversion.InputDriver -i testdata -o output1/data -v org.apache.mahout.math.RandomAccessSparseVector

如果你运行 mahout org.apache.mahout.clustering.conversion.InputDriver 它会列出它期望的参数。

希望这可以帮助。
另外,这是我写的一篇文章,用于解释我如何在 arff 文件上运行 kmeans 集群
http://mahout-hadoop.blogspot.com/2013/10/using-mahout-to-cluster-iris-data.html

于 2013-09-10T22:02:32.883 回答