问题描述:
在使用spark MLlib的时候,经常会使用MLUtils.loadLibSVMFile去加载libsvm格式的数据,如果你的libsvm数据格式不符合要求,比如,数据中索引不是按照升序排序:
这样的数据在运行程序的时候就会报错:
indices should be one-based and in ascending order
这个时候就需要你自己去排序,数据这么多,不可能手动去排序,可以利用scala去编写排序程序对数据进行排序,使其符合libsvm格式要求。
代码如下:
package others
import java.io.{File, PrintWriter}
import org.apache.spark.mllib.util.MLUtils
import org.apache.spark.{SparkContext, SparkConf}
/**
* Created by Administrator on 2017/4/27.
*/
object Sort {
def main(args: Array[String]) {
if(args.length<1){
System.err.println("Usage:<file>")
System.exit(1)
}
val input_File=args(0)
val output_file=args(1)
val conf=new SparkConf().setAppName("Sort")//设置本程序名称
//这里,我是通过maven构建的spark开发环境,然后打包到集群,通过spark-submit提交到yarn去执行的。
//如何通过idea的maven去构建spark,参考另一篇博客:http://blog.youkuaiyun.com/u013963380/article/details/71713582
//如何一步一步地在Intellij IDEA使用Maven搭建Spark开发环境,并基于Scala编写简单的spark中wordcount实例。
val sc=new SparkContext(conf)
//读取数据
val data = sc.textFile(input_File)
//通过排序方法重新map数据
val data_ok=data.map(line => trans(line))
//保存数据到指定文件
data_ok.repartition(1).saveAsTextFile(output_file)
}
def trans(line: String): String = {
//以第一条为例
//ne: String = 0 2:1 1:4 6:4 7:37 8:37 9:0 10:10 11:0 12:0 ...
//以空格分割
val cols = line.split(" ")
//把标签和特征分开
val label = cols(0);
val features = cols.slice(1, cols.length);
//对特征进行map,将下标和值分开,并用下标进行排序
//newFeatures: Array[(Double, Double)] = Array((1.0,4.0), (2.0,1.0), (6.0,4.0), (7.0,37.0), (8.0,37.0)....
val newFeatures = features.map(l => {
val k = l.split("\\:");
//转为double,用于排序
(k(0).toDouble, k(1).toDouble)
}).sortBy(_._1)
//重组字符串,,加上标签,并用空格分隔
//result: String = 0 1:4.0 2:1.0 6:4.0 7:37.0 8:37.0 9:0.0 10:10.0....
val result = label + " " + newFeatures.map(l => (l._1.toInt + ":" + l._2)).mkString(" ")
return result;
}
}