Для этого я использую NamedVectors.
Как вы знаете, прежде чем выполнять какую-либо кластеризацию с вашими данными, вы должны векторизовать их.
Это означает, что вы должны преобразовать свои данные в векторы Махоута, потому что это
данные, с которыми работают алгоритмы кластеризации.
Процесс векторизации будет зависеть от характера ваших данных, то есть векторизация текста не совпадает с
векторизовать числовые значения.
Ваши данные кажутся легко векторизованными, поскольку они имеют только ID и 4 числовых значения.
Вы можете написать задание Hadoop, которое принимает ваши входные данные, например, в виде файла CSV,
и выводит SequenceFile с уже векторизованными данными.
Затем вы применяете алгоритмы кластеризации Mahout к этому входу и сохраняете идентификатор (имя вектора) каждого вектора в результатах кластеризации.
Пример работы по векторизации ваших данных может быть реализован со следующими классами:
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);
}
}