//39932,40902,1,?,1,?,1,1,1,1,1,TRUE
/*
前两个字段是整数型ID,代表记录中匹配的两个病人;
后面9个值,代表病人记录中不同字段(姓名,生日,地址)的匹配值
最后一个字段:布尔。代表该行病人记录是否匹配。
我们用‘,’切割一下
*/
val p = head(5).split(',')
//p: Array[String] = Array(36950, 42116, 1, ?, 1, 1, 1, 1, 1, 1, 1, TRUE)
/*隐士类型转换:当调用scala对象方法时,如果定义该对象的类型中找不到方法定义,Scala编译器就将该对象转换成响应的方法定义的类的实例*/
val id1 = p(0).toInt
需要对9个字段值进行转换,可以先用Scala Array 类的slice方法提取一部分元素,然后调用map函数,将slice中每个元素的类型从String转成Double
val raws=p.slice(2,11)
//raws: Array[String] = Array(1, ?, 1, 1, 1, 1, 1, 1, 1)
raws.map(s=>s.toDouble)
/*
出错,主要是因为遇到了?,所以我们写一个函数来对它进行处理
java.lang.NumberFormatException: For input string: "?"
*/
def toDouble(s:String)={
if("?".equals(s)) Double.NaN else s.toDouble
}
//toDouble: (s: String)Double
val sorce = raws.map(toDouble)
//sorce: Array[Double] = Array(1.0, NaN, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)
结合所有,我们写一个方法,将之前的总结起来
def parse(line:String)={
val pieces = line.split(',')
val id1 = pieces(0).toInt
val id2 = pieces(1).toInt
val scores = pieces.slice(2,11).map(toDouble)
val matched = pieces(11).toBoolean
(id1,id2,scores,matched)
}
val tup = parse(line)
我们创建一个case class,方便取值:
case class MatchData(id1:Int,id2:Int,scores:Array[Double],matched:Boolean)
然后之后返回的时候,就不是元祖类型,而是MatchData类型;
def parse(line:String)={
val pieces = line.split(',')
val id1 = pieces(0).toInt
val id2 = pieces(1).toInt
val scores = pieces.slice(2,11).map(toDouble)
val matched = pieces(11).toBoolean
MatchData(id1,id2,scores,matched)
}
val tup = parse(line)
//这块的tup就已经是MatchData类型
//可以直接用过tup.id1 拿值了
接下来我们就可以调用函数。
val mds=head.filter(x=>!isHeader(x)).map(x=>parse(x))
//解析集群数据,再noheader上调用map函数:
val parsed = noheader.map(line=>parse(line))
//如果需要缓存,可以直接使用缓存,spark有自己的缓存机制
parsed.cache()
但是数据不一定在一台机器上,所以我们需要聚合,对其聚合时,数据传输的效率肯定是担心的一个问题。
val group = mds.groupBy(md=>md.matched)
/*
得到grouped变量中的值以后,就可以通过在grouped上调用mapValues方法得到计数。
*/
group.mapValues(x=>x.size).foreach(println)
创建直方图
连续变量的概要统计,如以下代码:
val stats =(0 until 9).map(i=>{
parsed.map(md=>md.scores(i)).filter(!isNaN(_)).stats()
})