1

我正在开发一个小型数据分析工具,并在此过程中练习/学习 Scala。但是我遇到了一个小问题。

假设数据类型:

X   Gr1     x_11    ... x_1n
X   Gr2     x_21    ... x_2n
..
X   GrK     x_k1    ... x_kn
Y   Gr1     y_11    ... y_1n
Y   Gr3     y_31    ... y_3n
..
Y   Gr(K-1)     ...

在这里,我的条目 (X,Y...) 可能存在也可能不存在于最多 K 个组中,每个组都有一系列值。我想做的很简单(理论上),我想将属于同一“实体”的行合并到不同的组中。因此,我不想以多行开头X,而是希望一行中的所有值都包含x_11x_kn列中。

然而,使事情变得复杂的是,并非所有实体都存在于所有组中。因此,无论哪里有“缺失数据”,我都想用例如零或一些表示缺失值的字符串来填充。因此,如果我在最多 3 个组中有 (X,Y,Z),我想要的类型 I 表如下:

X   x_11    x_12    x_21    x_22    x_31    x_32
Y   y_11    y_12    N/A     N/A     y_31    y_32
Z   N/A     N/A     z_21    z_22    N/A     N/A

我一直在试图解决这个问题,有没有一种聪明的方法可以使用 List 函数来解决这个问题?


我写了这个简单的循环:

for {
  (id, hitlist) <- hits.groupBy(_.acc)
  h <- hitlist
} println(id + "\t" + h.sampleId + "\t" + h.ratios.mkString("\t"))

能够生成类似于上面示例的表。请注意,我的原始数据具有不同的格式和布局,但这与手头的问题无关,因此我跳过了有关解析的所有步骤。我应该能够以groupBy更好的方式使用实际上为我解决了这个问题,但我似乎无法到达那里。

然后我修改了我的循环映射hitsratios并将它们附加到另一个:

for ((id, hitlist) <- hits.groupBy(_.acc)){
  val l = hitlist.map(_.ratios).foldRight(List[Double]()){
    (l1: List[Double], l2: List[Double]) => l1 ::: l2
  }
  println(id + "\t" + l.mkString("\t"))
  //println(id + "\t" + h.sampleId + "\t" + h.ratios.mkString("\t"))
}

这让我更近了一步,但仍然没有雪茄!我得到一个锯齿状的桌子​​,而不是一个完全填充的“矩阵”。以上面的例子为例:

X   x_11    x_12    x_21    x_22    x_31    x_32
Y   y_11    y_12    y_31    y_32
Z   z_21    z_22

关于如何填充表格以使各个组的值相互对齐的任何想法?我应该能够使用_.sampleId,它为每个“命中”保存“组成员IP”,但我不确定如何准确。'hits' 是一个 List 类型Hit,它实际上是每一行的包装器,为获取单个值提供了方便的方法,因此本质上是一个具有“命名索引”的元组(例如.acc.sampleId..)

(我想在不硬编码组数的情况下解决这个问题,因为它可能会因情况而异)

谢谢!

4

2 回答 2

2

这是一个人为的例子,但我想你可以看到这是怎么回事:

  case class Hit(acc:String, subAcc:String, value:Int)

  val hits = List(Hit("X", "x_11", 1), Hit("X", "x_21", 2), Hit("X", "x_31", 3))
  val kMax = 4
  val nMax = 2

  for {
    (id, hitlist) <- hits.groupBy(_.acc)
    k <- 1 to kMax
    n <- 1 to nMax
  } yield {
    val subId = "x_%s%s".format(k, n)
    val row = hitlist.find(h => h.subAcc == subId).getOrElse(Hit(id, subId, 0))

    println(row)
  }

//Prints
Hit(X,x_11,1)
Hit(X,x_12,0)
Hit(X,x_21,2)
Hit(X,x_22,0)
Hit(X,x_31,3)
Hit(X,x_32,0)
Hit(X,x_41,0)
Hit(X,x_42,0)

如果您在hits列表中提供更多信息,那么我们可能会提供更准确的信息。

于 2013-07-19T15:10:30.823 回答
0

I have managed to solve this problem with the following code, I am putting it here as an answer in case someone else runs into a similar problem and requires some help. The use of find() from Noah's answer was definitely very useful, so do give him a +1 in case this code snippet helps you out.

val samples = hits.groupBy(_.sampleId).keys.toList.sorted
for ((id, hitlist) <- hits.groupBy(_.acc)) {
  val ratios =
    for (sample <- samples)
      yield hitlist.find(h => h.sampleId == sample).map(_.ratios)
      .getOrElse(List(Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN))
  println(id + "\t" + ratios.flatten.mkString("\t"))
}

I figure it's not a very elegant or efficient solution, as I have two calls to groupBy and I would be interested to see better solutions to this problem.

于 2013-07-22T07:21:50.840 回答