/ / Transformacje map w scali (częstotliwości tagów obliczeniowych) - scala

Transformacje map w scala (częstotliwość obliczeń tagów) - scala

Nadal nie jestem biegły w scali, ale używam go do przetwarzania niektórych danych, które wczytałem z pliku do następującej struktury danych:

Map[Id, (Set[Category], Set[Tag])]

gdzie

type Id = String

type Category = String

type Tag = String

Zasadniczo każdy klawisz w Map jest unikalnym identyfikatorem jednostki powiązanym z zestawem kategorii i zestawem znaczników.

Moje pytanie brzmi: co jest najlepsze (= najwięcej wydajny i najbardziej idiomatyczny) sposób obliczania:

  • oznacza częstotliwości we wszystkich jednostkach (type TagsFrequencies = Map[Tag, Double])
  • tagi częstotliwości na kategorię (Map[Category, TagsFrequencies])

Oto moja próba:

def tagsFrequencies(tags: List[Tag]): TagsFrequencies =
tags.groupBy(t => t).map(
kv => (kv._1 -> kv._2.size.toDouble / tags.size.toDouble))

def computeTagsFrequencies(data: Map[Id, (Set[Category], Set[Tag])]): TagsFrequencies = {
val tags = data.foldLeft(List[Tag]())(
(acc, kv) => acc ++ kv._2._2.toList)
tagsFrequencies(tags)
}

def computeTagsFrequenciesPerCategory(data: Map[Id, (Set[Category], Set[Tag])]): Map[Category, TagsFrequencies] = {

def groupTagsPerCategory(data: Map[Id, (Set[Category], Set[Tag])]): Map[Category, List[Tag]] =
data.foldLeft(Map[Category, List[Tag]]())(
(acc, kv) => kv._2._1.foldLeft(acc)(
(a, category) => a.updated(category, kv._2._2.toList ++ a.getOrElse(category, Set.empty).toList)))

val tagsPerCategory = groupTagsPerCategory(data)
tagsPerCategory.map(tpc => (tpc._1 -> tagsFrequencies(tpc._2)))
}

Jako przykład rozważ

val data = Map(
"id1" -> (Set("c1", "c2"), Set("t1", "t2", "t3")),
"id2" -> (Set("c1"), Set("t1", "t4")))

następnie:

tagi częstotliwości we wszystkich jednostkach to:

Map(t3 -> 0.2, t4 -> 0.2, t1 -> 0.4, t2 -> 0.2)

a tagi częstotliwości na kategorię to:

Map(c1 -> Map(t3 -> 0.2, t4 -> 0.2, t1 -> 0.4, t2 -> 0.2), c2 -> Map(t3 -> 0.3333333333333333, t1 -> 0.3333333333333333, t2 -> 0.3333333333333333))

Odpowiedzi:

2 dla odpowiedzi № 1

Oto przepisanie idiomu, niekoniecznie wydajności. Uczyniłbym twoją pierwszą metodę trochę bardziej ogólną ( Iterable argument), użyj identity zamiast t => t, I użyć mapValues:

def tagsFrequencies(tags: Iterable[Tag]): TagsFrequencies =
tags.groupBy(identity).mapValues(_.size / tags.size.toDouble)

Ponieważ teraz to trwa Iterable[Tag], możesz go użyć do wyczyszczenia drugiej metody:

def computeTagsFrequencies(data: Map[Id, (Set[Category], Set[Tag])]) =
tagsFrequencies(data.flatMap(_._2._2))

I podobnie dla ostatniej metody:

def computeTagsFrequenciesPerCategory(data: Map[Id, (Set[Category], Set[Tag])]) =
data.values.flatMap {
case (cs, ts) => cs.map(_ -> ts)
}.groupBy(_._1).mapValues(v => tagsFrequencies(v.flatMap(_._2)))

Żadna z tych zmian nie powinna wpływać na wydajność w żaden znaczący sposób, ale powinieneś oczywiście dokonać porównania we własnej aplikacji.