Scala 火花随机数生成 我编写了一个必须考虑随机数来模拟伯努利分布的方法。我正在使用random.nextDouble生成一个介于0和1之间的数字,然后根据给定概率参数的该值做出决策

Scala 火花随机数生成 我编写了一个必须考虑随机数来模拟伯努利分布的方法。我正在使用random.nextDouble生成一个介于0和1之间的数字,然后根据给定概率参数的该值做出决策,scala,random,apache-spark,spark-dataframe,Scala,Random,Apache Spark,Spark Dataframe,我的问题是Spark在for循环映射函数的每次迭代中生成相同的随机数。我正在使用DataFrameAPI。我的代码遵循以下格式: val myClass = new MyClass() val M = 3 val myAppSeed = 91234 val rand = new scala.util.Random(myAppSeed) for (m <- 1 to M) { val newDF = sqlContext.createDataFrame(myDF .map{ro

我的问题是Spark在for循环映射函数的每次迭代中生成相同的随机数。我正在使用
DataFrame
API。我的代码遵循以下格式:

val myClass = new MyClass()
val M = 3
val myAppSeed = 91234
val rand = new scala.util.Random(myAppSeed)

for (m <- 1 to M) {
  val newDF = sqlContext.createDataFrame(myDF
    .map{row => RowFactory
      .create(row.getString(0),
        myClass.myMethod(row.getString(2), rand.nextDouble())
    }, myDF.schema)
}

我做了一些研究,似乎这与Sparks的确定性有关。

只需使用SQL函数
rand

import org.apache.spark.sql.functions._

//df: org.apache.spark.sql.DataFrame = [key: int]

df.select($"key", rand() as "rand").show
+---+-------------------+
|key|               rand|
+---+-------------------+
|  1| 0.8635073400704648|
|  2| 0.6870153659986652|
|  3|0.18998048357873532|
+---+-------------------+


df.select($"key", rand() as "rand").show
+---+------------------+
|key|              rand|
+---+------------------+
|  1|0.3422484248879837|
|  2|0.2301384925817671|
|  3|0.6959421970071372|
+---+------------------+

重复相同序列的原因是,在对数据进行分区之前,使用种子创建并初始化随机生成器。然后,每个分区从相同的随机种子开始。也许这不是最有效的方法,但以下方法应该有效:

val myClass = new MyClass()
val M = 3

for (m <- 1 to M) {
  val newDF = sqlContext.createDataFrame(myDF
    .map{ 
       val rand = scala.util.Random
       row => RowFactory
      .create(row.getString(0),
        myClass.myMethod(row.getString(2), rand.nextDouble())
    }, myDF.schema)
}
val myClass=new myClass()
val M=3
对于(m)工厂
.create(row.getString(0),
myClass.myMethod(row.getString(2),rand.nextDouble())
},myDF.schema)
}
根据,最佳解决方案不是将
新的scala.util.Random
放在地图内部,也不是完全放在地图外部(即驱动程序代码中),而是放在中间
地图分区索引中:

import scala.util.Random
val myAppSeed = 91234
val newRDD = myRDD.mapPartitionsWithIndex { (indx, iter) =>
   val rand = new scala.util.Random(indx+myAppSeed)
   iter.map(x => (x, Array.fill(10)(rand.nextDouble)))
}

使用Spark数据集API,可能用于累加器:

df.withColumn("_n", substring(rand(),3,4).cast("bigint"))

这并没有完全解决我的问题,但它是一个优雅的解决方案,我将来可能会使用它,因此+1我对它进行了轻微修改以解决我的问题。我将随机val传递到我的方法中,并从中生成随机数。这解决了我的问题,但出于可序列化的原因,我不得不使用
java.util.Random
import scala.util.Random
val myAppSeed = 91234
val newRDD = myRDD.mapPartitionsWithIndex { (indx, iter) =>
   val rand = new scala.util.Random(indx+myAppSeed)
   iter.map(x => (x, Array.fill(10)(rand.nextDouble)))
}
df.withColumn("_n", substring(rand(),3,4).cast("bigint"))