Apache spark 有没有一种方法可以精确地对Spark RDD进行采样,以获得指定数量的元素而不是百分比?

Apache spark 有没有一种方法可以精确地对Spark RDD进行采样,以获得指定数量的元素而不是百分比?,apache-spark,rdd,Apache Spark,Rdd,我目前需要在Spark中为k元素随机抽取RDD中的项目。我注意到有takeSample方法。方法签名如下所示 takeSample(withReplacement: Boolean, num: Int, seed: Long = Utils.random.nextLong): Array[T] val rdd = sc.textFile("some/path") //creates the rdd val N = rdd.count() //total items in the rdd va

我目前需要在Spark中为k元素随机抽取RDD中的项目。我注意到有
takeSample
方法。方法签名如下所示

takeSample(withReplacement: Boolean, num: Int, seed: Long = Utils.random.nextLong): Array[T] 
val rdd = sc.textFile("some/path") //creates the rdd
val N = rdd.count() //total items in the rdd
val fraction = k / N.toDouble
val sampledRdd = rdd.sample(false, fraction, 67L)
但是,这不会返回RDD。还有另一种采样方法返回RDD,
sample

sample(withReplacement: Boolean, fraction: Double, seed: Long = Utils.random.nextLong): RDD[T]
我不想使用第一种方法
takeSample
,因为它不会返回RDD,并且会将大量数据拉回到驱动程序(内存问题)。我继续使用
示例
方法,但我必须计算
分数
(百分比),如下所示

takeSample(withReplacement: Boolean, num: Int, seed: Long = Utils.random.nextLong): Array[T] 
val rdd = sc.textFile("some/path") //creates the rdd
val N = rdd.count() //total items in the rdd
val fraction = k / N.toDouble
val sampledRdd = rdd.sample(false, fraction, 67L)
这种方法/方法的问题是,我可能无法获得具有完全k个项目的RDD。例如,如果我们假设N=10,那么

  • k=2,分数=20%,抽样项目=2
  • k=3,分数=30%,抽样项目=3
  • 等等
但是如果N=11,那么

  • k=2,分数=18.1818%,抽样项目=
  • k=3,分数=27.2727%,抽样项目=
在最后一个示例中,对于分数=18.1818%,结果RDD中将包含多少项

另外,这是关于分数论点的说法

expected size of the sample as a fraction of this RDD's size - without replacement: probability that each element is chosen; fraction must be [0, 1] - with replacement: expected number of times each element is chosen; fraction must be greater than or equal to 0 那么,它是
k/N
还是
1/N
?文档似乎指向了样本大小和抽样概率的所有不同方向

最后,文档注释

这并不能保证精确地提供给定RDD计数的分数

这让我回到了我最初的问题/担忧:如果RDDAPI不能保证从RDD中精确地采样k个项目,我们如何有效地做到这一点

当我写这篇文章时,我发现已经有人问了几乎相同的问题。我觉得被接受的答案不可接受。在这里,我还想澄清分数论点


我想知道是否有一种方法可以使用数据集和数据帧来实现这一点

这个解决方案并没有那么漂亮,但我希望它能有助于思考。 诀窍是使用额外的分数,并获得第k个最大分数作为阈值

val k = 100
val rdd = sc.parallelize(0 until 1000)
val rddWithScore = rdd.map((_, Math.random))
rddWithScore.cache()
val threshold = rddWithScore.map(_._2)
  .sortBy(t => t)
  .zipWithIndex()
  .filter(_._2 == k)
  .collect()
  .head._1
val rddSample = rddWithScore.filter(_._2 < threshold).map(_._1)
rddSample.count()
valk=100
val rdd=sc.parallelize(0到1000)
val rddWithScore=rdd.map(((uu,Math.random))
rddWithScore.cache()
val threshold=rddWithScore.map(u._2)
.sortBy(t=>t)
.zipWithIndex()
.filter(u._2==k)
.collect()
.头._1
val rddSample=rddWithScore.filter(u._2
输出将是

k: Int = 100
rdd: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[58] at parallelize at <console>:31
rddWithScore: org.apache.spark.rdd.RDD[(Int, Double)] = MapPartitionsRDD[59] at map at <console>:32
threshold: Double = 0.1180443408900893
rddSample: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[69] at map at <console>:40
res10: Long = 100
k:Int=100
rdd:org.apache.spark.rdd.rdd[Int]=ParallelCollectionRDD[58]at parallelize at:31
rddWithScore:org.apache.spark.rdd.rdd[(Int,Double)]=MapPartitionsRDD[59]位于map at:32
阈值:双=0.1180443408900893
rddSample:org.apache.spark.rdd.rdd[Int]=MapPartitionsRDD[69]位于map at:40
res10:Long=100