涉及成对距离的方程的Spark方法

时间:2018-03-17 13:53:57

标签: scala apache-spark user-defined-functions

我有一段伪代码,我一直试图在Spark中实现(目前使用Scala,但很乐意在需要时使用其他语言)大约一个星期,我完全陷入困境。导致我出现问题的伪代码部分是(对图像道歉,但没有MathOverflow的LaTeX选项,它似乎最清楚):pseudocode

  • 每行包含id1id2obxy
  • 我使用Window分区(id1id2),每个窗口都有多个(x:整数,y:整数和ob:Double)构成一个单元格或c
  • 该循环适用于k = 1 ... m,其中m是窗口中的行数。
  • 行的顺序与我的目的无关(st值会受到影响,但过去的工作表明它在最终结果中没有可观察到的差异。)
  • 以前计算的所有行st> 0是K的一部分。由于st> = 0,因此包含所有先前计算的行似乎是安全的。
  • alpha是固定参数。
  • Dis_grid目前是xy坐标之间的欧几里德距离UDF,但如果这样可以使实施更容易,则它可以是不同的距离度量。

我无法弄清楚如何:

  • 在窗口中为第一行指定一个不同的值。
  • 使用先前计算的行的st来计算下一行的st
  • 计算行之间的各个成对距离,使其成为st公式的一部分。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

我很难准确地遵循你想要做的事情(我认为命令在组/窗口内重要),所以这可能不对,但这些是我的想法。首先,我认为在Dataset操作而不是DataFrame操作方面,很多更容易思考。 (如果你想在DataFrame世界中这样做,我想你想看一下用户定义的聚合函数(UDAF)。)因为DataFrame只是Dataset[Row],所以它都是相当于,但我要定义一个Cell案例类并使用Dataset[Cell]来简化事情,所以请放纵我。

case class Cell(id1: Int, id2: Int, ob: Double, x: Int, y: Int)

想象一下,我们有一个Dataset[Cell],称之为ds。我们希望通过成对(id1,id2)对其进行分组,然后在每个组上应用一些函数(如果f调用),最后得到Dataset[(Cell, Double)]。 (我认为这就是你想要的。在这种情况下,我很难看到组内行/单元的顺序无关紧要。)这相当于

ds.groupByKey(c => (c.id1, c.id2).flatMapGroups(f)

那么f是什么?它需要为组中的每个单元格计算st。如果我正确理解,则求和的工作方式如下:对于单元格i,对所有st(j) * alpha^dist(i, j)求和j < i。从单元格的观察值中减去该总和,并从0减去最大值,得到st。假设你有一个函数dist来计算两个单元格之间的距离,作为一个函数,所有单元格,先前计算的st和单元格c,求和项可以用作:

def stSum(cells: List[Cell], sts: List[Double], c: Cell): Double =
    sts.zipWithIndex.map{ case (st, l) => 
        st * math.pow(alpha, dist(c, cells(l)))
    }.sum

然后,对于单元格cstmath.max(0, c.ob - stSum(cells, sts, c)),其中cells是该组中的所有单元格,sts是一个列表&#34;早期&#34;的st值细胞。然后,我们可以使用st计算foldLeft s的(有序)列表:

cells.foldLeft(List()){ case (sts, c) =>
  sts :+ math.max(0, c.ob - stSum(cells, sts, c))    
}

然后我们可以汇编f

def f(key: (Int, Int), cellIterable: Iterable[Cell]): List[(Cell, Double)] = {
  val cells = cellIterable.toList
  val sts = cells.foldLeft(List()){ case (stAcc, c) =>
    stAcc :+ math.max(0, c.ob - stSum(cells, stAcc, c))    
  }
  cells.zip(sts)
}

我们需要将cellIterable转换为列表,因为我们需要通过索引访问其元素,因此我们需要一个支持它的类型。它通常在Scala中更快地添加到列表而不是追加,并且可以反向建立st的列表,但它需要一些索引杂耍。最后需要注意的是,f中的flatMapGroups需要使用元组,而我上面写的f没有,所以你最终得到了

ds.groupByKey(c => (c.id1, c.id2).flatMapGroups(Function.tupled(f))