如何从Scala列表或数组中随机抽样?

时间:2015-10-04 09:59:09

标签: arrays list scala apache-spark sample

我想从Scala列表或数组(不是RDD)中随机采样,样本大小可能比列表或数组的长度长得多,我怎样才能高效?因为样本量可能非常大,并且需要在很多次进行采样(在不同的列表/数组上)。

我知道Spark RDD我们可以使用takeSample()来实现它,是否有Scala列表/数组的等价物?

非常感谢。

6 个答案:

答案 0 :(得分:24)

易于理解的版本如下所示:

import scala.util.Random

Random.shuffle(list).take(n)
Random.shuffle(array.toList).take(n)

// Seeded version
val r = new Random(seed)
r.shuffle(...)

答案 1 :(得分:3)

对于数组:

import scala.util.Random
import scala.reflect.ClassTag

def takeSample[T:ClassTag](a:Array[T],n:Int,seed:Long) = {
  val rnd = new Random(seed)
  Array.fill(n)(a(rnd.nextInt(a.size)))
}

根据种子制作随机数生成器(rnd)。然后,使用0中的随机数填充数组,直到数组的大小。

最后一步是将每个随机值应用于输入数组的索引运算符。在REPL中使用它可能如下所示:

scala> val myArray = Array(1,3,5,7,8,9,10)
myArray: Array[Int] = Array(1, 3, 5, 7, 8, 9, 10)

scala> takeSample(myArray,20,System.currentTimeMillis)
res0: scala.collection.mutable.ArraySeq[Int] = ArraySeq(7, 8, 7, 3, 8, 3, 9, 1, 7, 10, 7, 10,
1, 1, 3, 1, 7, 1, 3, 7)

对于列表,我只需将列表转换为Array并使用相同的函数。我怀疑你无论如何都可以为列表提高效率。

值得注意的是,使用列表的相同函数需要花费O(n ^ 2)时间,而将列表首先转换为数组需要花费O(n)时间

答案 2 :(得分:1)

使用for comprehension,对于给定的数组xs,如下所示,

for (i <- 1 to sampleSize; r = (Math.random * xs.size).toInt) yield a(r)

注意,随机生成器在此处生成单位间隔内的值,这些值被缩放到超出数组大小的范围,并转换为Int以便在数组上进行索引。

注意对于纯函数随机生成器,请考虑Functional Programming in Scala中的状态Monad方法,讨论here

注意另请考虑另一个纯函数随机值生成器NICTA,例如here说明了它的使用。

答案 3 :(得分:1)

使用经典递归。

import scala.util.Random

def takeSample[T](a: List[T], n: Int): List[T] = {
    n match {
      case n: Int if n <= 0 => List.empty[T]
      case n: Int => a(Random.nextInt(a.size)) :: takeSample(a, n - 1)
    }
}

答案 4 :(得分:1)

如果你想在没有替换的情况下对进行采样 - 使用random进行压缩,排序O(n*log(n),丢弃randoms,采取

import scala.util.Random
val l = Seq("a", "b", "c", "d", "e")
val ran = l.map(x => (Random.nextFloat(), x))
  .sortBy(_._1)
  .map(_._2)
  .take(3)

答案 5 :(得分:0)

没有测试性能,但是以下代码是进行采样的一种简单而优雅的方法,我相信这里的许多代码只是可以帮助您获得采样代码。只需根据最终样本的大小更改“范围”即可。如果pseude-randomness不足以满足您的需要,则可以在内部列表中使用take(1)并扩大范围。

Random.shuffle((1 to 100).toList.flatMap(x => (Random.shuffle(yourList))))