scala 查找键控序列的前 k 个元素
scala find top-k elements for a keyed sequence
对于第一个元素构成键的事物序列:
val things = Seq(("key_1", ("first", 1)),("key_1", ("first_second", 11)), ("key_2", ("second", 2)))
我想统计一个键出现的频率,然后只保留前k个元素。
在 pandas 或数据库中,我会:
- 计数
- 将结果与原始结果合并并过滤
在 Scala 中,第一部分可以通过以下方式处理:
things.groupBy(identity).mapValues(_.size)
这里的第一位是:
things.groupBy(_._1).mapValues(_.map( _._2 ))
但是我不确定第二步。
在上面的示例中,当查看 top-1 键时 key_1
出现两次并因此被选中。
期望的输出结果是 top-k 键元组的第二个元素:
Seq(("first", 1),("first_second", 11))
编辑
我需要一个适用于 2 的解决方案。11.x。
看起来像:
things.groupBy(_._1)
.mapValues(e => (e.map(_._2).size, e.map(_._2))).toSeq.map(_._2)
.sortBy(_._1).reverse.take(2).flatMap(_._2)
计算所需的输出
此方法首先按键分组以获得键到原始项的映射。
您还可以使用 OrderedMap 或 PriorityQueue 进行更高效的前 N 项计算,但如果元素不多,那么简单的 sortBy 也可以,如图所示。
def valuesOfNMostFrequentKeys(things: Seq[(String, (String, Int))], N: Int = 1) = {
val grouped: Map[String,Seq[(String, (String, Int))]] = things.groupBy(_._1)
// "map" array of counts per keys to KV Tuples
val countToTuples:Array[(Int, Seq[(String, (String, Int))])] = grouped.map((kv: (String, Seq[(String, (String, Int))])) => (kv._2.size, kv._2)).toArray
// sort by count (first item in tuple) descending and take top N
val sortByCount:Array[(Int, Seq[(String, (String, Int))])] = countToTuples.sortBy(-_._1)
val topN:Array[(Int, Seq[(String, (String, Int))])] = sortByCount.take(N)
// extract inner (String, Int) item from list of keys and values, and flatten
topN.flatMap((kvList: (Int, Seq[(String, (String, Int))])) => kvList._2.map(_._2))
}
valuesOfNMostFrequentKeys(things)
输出:
valuesOfNMostFrequentKeys: (things: Seq[(String, (String, Int))], N: Int)Array[(String, Int)]
res44: Array[(String, Int)] = Array((first,1), (first_second,11))
上面的注释是一个数组,您可能想要这样做 toSeq
——但这在 Scala 2.11 中有效。
对于第一个元素构成键的事物序列:
val things = Seq(("key_1", ("first", 1)),("key_1", ("first_second", 11)), ("key_2", ("second", 2)))
我想统计一个键出现的频率,然后只保留前k个元素。
在 pandas 或数据库中,我会:
- 计数
- 将结果与原始结果合并并过滤
在 Scala 中,第一部分可以通过以下方式处理:
things.groupBy(identity).mapValues(_.size)
这里的第一位是:
things.groupBy(_._1).mapValues(_.map( _._2 ))
但是我不确定第二步。
在上面的示例中,当查看 top-1 键时 key_1
出现两次并因此被选中。
期望的输出结果是 top-k 键元组的第二个元素:
Seq(("first", 1),("first_second", 11))
编辑
我需要一个适用于 2 的解决方案。11.x。
看起来像:
things.groupBy(_._1)
.mapValues(e => (e.map(_._2).size, e.map(_._2))).toSeq.map(_._2)
.sortBy(_._1).reverse.take(2).flatMap(_._2)
计算所需的输出
此方法首先按键分组以获得键到原始项的映射。
您还可以使用 OrderedMap 或 PriorityQueue 进行更高效的前 N 项计算,但如果元素不多,那么简单的 sortBy 也可以,如图所示。
def valuesOfNMostFrequentKeys(things: Seq[(String, (String, Int))], N: Int = 1) = {
val grouped: Map[String,Seq[(String, (String, Int))]] = things.groupBy(_._1)
// "map" array of counts per keys to KV Tuples
val countToTuples:Array[(Int, Seq[(String, (String, Int))])] = grouped.map((kv: (String, Seq[(String, (String, Int))])) => (kv._2.size, kv._2)).toArray
// sort by count (first item in tuple) descending and take top N
val sortByCount:Array[(Int, Seq[(String, (String, Int))])] = countToTuples.sortBy(-_._1)
val topN:Array[(Int, Seq[(String, (String, Int))])] = sortByCount.take(N)
// extract inner (String, Int) item from list of keys and values, and flatten
topN.flatMap((kvList: (Int, Seq[(String, (String, Int))])) => kvList._2.map(_._2))
}
valuesOfNMostFrequentKeys(things)
输出:
valuesOfNMostFrequentKeys: (things: Seq[(String, (String, Int))], N: Int)Array[(String, Int)]
res44: Array[(String, Int)] = Array((first,1), (first_second,11))
上面的注释是一个数组,您可能想要这样做 toSeq
——但这在 Scala 2.11 中有效。