コンサルでデータサイエンティスト

仕事でPythonを書いてます。機械学習、Webマーケティングに興味があります。趣味は旅です。

Scalaの配列(リスト)の各要素の出現個数をカウントする

Scalaの配列(リスト)の各要素の出現個数をカウントする方法について調べたのでまとめます。Pythonであればcollections.Counterやcountメソッドで実現できることを、Scalaでは関数型言語の思想に近い形で記述することができます。記事の後半ではおまけとして、配列内のカテゴリ変数の分かれ方を表す指標であるジニ係数(Gini Score)の算出方法についても書いています。

Scalaの配列(リスト)の各要素の出現個数をカウント

次のような長さ10の文字列配列があるとします。

val s = Seq("A", "A", "A", "B", "A", "C", "A", "A", "A", "B") 


この配列中の各要素の出現回数は次のように求めることができます。なお、ここでの出力はMap型になります。

val cntMap = s.groupBy(identity).mapValues(_.size)
cntMap: Map(A -> 7, C -> 1, B -> 2)


各要素の個数についてアクセスしたい場合は次のように書きます。要素“A”の個数は7個であることがわかります。

cntMap("A")
res: 7

配列内のカテゴリ変数のばらつき度合い(分散)をジニ係数で求める

ジニ係数とは配列内の各要素がどの程度ばらついているかを求める指標であり、0から1の範囲をとります。すべての要素が”A”であればジニ係数は0になり、すべての要素が互いに異なる場合は1に近い値をとります。
ジニ係数の詳細については次の記事に記載しています。
http://hktech.hatenablog.com/entry/2018/10/05/004235

ジニ係数は次の式で求めることができます。
 1-\sum_{i=1}^{K}P^2(C_i|t)

ここでは配列全体の要素数が必要となるので、次のように求めます。

val seqLen = s.size


算出式中の P^2(C_i|t)部分については、次のように求められます。

Math.pow(v.toDouble/seqLen, 2)


最終的なジニ係数の算出はfoldLeft関数を使って以下のように書くことができます。

val giniScore = 1.0 - cntMap.values.foldLeft(0.0)((sum, v) => 
  sum + Math.pow(v.toDouble/seqLen, 2))

まとめ

Scalaの配列の各要素の出現個数をカウントする方法についてご紹介しました。また、配列内のばらつき度合いを表すジニ係数の求め方についてもまとめました。メソッドをチェーンすることで複雑な処理も関数風に1行で書くことでScalaの特徴を活かすことができるので、本記事での記述方法を参考にしてみてください。

実践Scala入門

実践Scala入門