Upgrade to Pro — share decks privately, control downloads, hide ads and more …

HyperLogLog

xorphitus
November 18, 2015

 HyperLogLog

HyperLogLog の解説を試みました。

xorphitus

November 18, 2015
Tweet

More Decks by xorphitus

Other Decks in Programming

Transcript

  1. HyperLogLog とは • カーディナリティの推定値を求めるアルゴリズム ◦ MultiSet {1, 1, 2, 3,

    4, 4, 4} なら 4 • 巨大な入力に対して、少ないメモリ消費量で値を算出できる ◦ イメージとしては, n+1 番目の入力が来たときのカーディナリティを Cn+1 とすると ▪ Cn+1 = f(xn+1, Cn) みたいな ▪ x1,...,xn は捨てて C のその時の値だけ保持していればよい ◦ Web みたいにどんどん次の入力がくるパターンに向いている • 乱択的である ◦ 元の入力ハッシュを値をとり , その一部の bit 列を使って ▪ 複数ある入れ物に振り分けたり ▪ 推定値を算出したり ◦ でもって最後に統計的手法で最終的な値を算出する
  2. 基本的な考え方 1. 元の入力 (MultiSet) を Μ とする 2. Μ を

    m 個の部分集合 Μ1,...,Μm に分ける 3. Μ1,...,Μm についてカーディナリティの推定値を求める 4. Μ1,...,Μm の推定値の調和平均を取る • Μi のカーディナリティを求める時, 古い入力データは保持せず済むのでメモリが節 約できる • Μ の各要素がどの部分集合に振り分けられるかは乱択的である
  3. • m = 2^b with b∈Z>0 ◦ となる m と

    b を考える • m 個のレジスタ M[1]...M[m] を用意する • for v∈Μ do ◦ let x = hash(v) ◦ let j = 1 + (v の先頭 b bit) ◦ v をレジスタ M[j] の値の算出に用いる ▪ m と b の定義を考えると、j の値は 1,...,m の範囲であると分かりますね 部分集合への振り分けについて
  4. • m = 2^b with b∈Z>0 ◦ となる m と

    b を考える • m 個のレジスタ M[1]...M[m] を用意する • for v∈Μ do ◦ let x = hash(v) ◦ let j = 1 + (v の先頭 b bit) ◦ let w = v の先頭 b+1 bit 目以降 ◦ M[j] = Max(M[j], ρ(w)) ▪ where ρ(s), s∈任意のbit列, 先頭から数えて最初に 1 になった桁の数 • s = 000101110 ならば 4 ▪ つまり ρ(w) の最大値だけ覚えておいて他のデータは捨てる で、カーディナリティどうやって求めるの? 1
  5. • m = 2^b with b∈Z>0 ◦ となる m と

    b を考える • m 個のレジスタ M[1]...M[m] を用意する • for v∈Μ do ◦ let x = hash(v) ◦ let j = 1 + (v の先頭 b bit) ◦ let w = v の先頭 b+1 bit 目以降 ◦ M[j] = Max(M[j], ρ(w)) ▪ where ρ(s), s∈任意のbit列, 先頭から数えて最初に 1 になった桁の数 • カーディナリティ = α_m * m * (2^(-M[1])...2^(-M[m]))の調和平均 ◦ α_m は m に依存する値で, この掛け算で正規化をしている (面倒だから中身は割愛 ) で、カーディナリティどうやって求めるの? 2
  6. ?!

  7. • m = 2^b with b∈Z>0 ◦ となる m と

    b を考える • m 個のレジスタ M[1]...M[m] を用意する • for v∈Μ do ◦ let x = hash(v) ◦ let j = 1 + (v の先頭 b bit) ◦ let w = v の先頭 b+1 bit 目以降 ◦ M[j] = Max(M[j], ρ(w)) ▪ where ρ(s), s∈任意のbit列, 先頭から数えて最初に 1 になった桁の数 • カーディナリティ = α_m * m * (2^(-M[1])...2^(-M[m]))の調和平均 ◦ α_m は m に依存する値で, この掛け算で正規化をしている (面倒だから中身は割愛 ) ちょっと待て イミフ
  8. • for v∈Μ do ◦ let x = hash(v) ◦

    let j = 1 + (v の先頭 b bit) ◦ let w = v の先頭 b+1 bit 目以降 ◦ M[j] = Max(M[j], ρ(w)) ▪ where ρ(s), s∈任意のbit列, 先頭から数えて最初に 1 になった桁の数 • Μ の j 番目の部分集合の各要素について, b+1 桁目から 0 が連続しているのは 最大で何回か, に1を足した数が M[j] ◦ 0 の連続数…つまり「レア度」だ ◦ M[j] は部分集合 Μj の中で最もレア, つまり重複しにくいものを指している まず M[j] とは何なのか
  9. • Μ の j 番目の部分集合の各要素について, b+1 桁目から 0 が連続しているのは 最大で何回か,

    に1を足した数が M[j] ◦ 01 の列において 0 が k 回連続する確率は 2^(-k) なので ◦ M[j] が得られる確率は 2^(-M[j]+1) である ▪ つまり ▪ M[j] よりも 0 が連続する (すなわち重複しない ) 値が次にくる確率は • 2^(-M[j]) • ここで, 確率 p の事象 A が発生するまで試行を続けた場合の, A が発生するまで にかかる試行数の期待値が 1/p であることを考えると ◦ 平均して 1/(2^(-M[j])) すなわち 2^(M[j]) 個の入力があれば Μj のカーディナリティは増加する M[j] とはレア度?
  10. • 平均して 2^(M[j]) 個の入力があれば Μj のカーディナリティは増加する ◦ j は 1,...,m

    まであるので, これらの調和平均をとることでより偏りをなくす ◦ 2^(M[j])の調和平均 は mZ と置く (m 個の要素だと分子が m になるので) ▪ 割合の場合は算術平均だと変な値になるので • ここで部分集合 Μj について関数 Max を以下のように定義する ◦ Max(Μj) = max(ρ(x)), x∈Μj ◦ すると恐らく近似的に以下が成り立つ ◦ 2^(Max(Μj)) = mZ M[j] が何だか結局分からんけどまあいいか
  11. • (再掲) 部分集合Μj について関数 Max を以下のように定義する ◦ Max(Μj) = max(ρ(x)),

    x∈Μj ◦ このとき ρ が bit 列において 0 の連続数+1 であることを考えると ◦ nj を Μj のカーディナリティとして ◦ Max(Μj) = log2(nj) ▪ 最大 0 連続数と, カーディナリティの数値の bit 長 が一致する?? • ここで Μ のカーディナリティを n とするとレジスタ数 m に均一に分散するとしたら Μj のカーディナリティは n/m となるから ◦ Max(Μj) = log2(n/m) ◦ ここで前ページで導出した 2^(Max(Μj)) = mZ を用いると ◦ n = (m^2)Z 別の切り口から
  12. • だいぶ前のイミフだった式を再掲 ◦ カーディナリティ = α_m * m * (2^(-M[1])...2^(-M[m]))の調和平均

    • ここで上記の調和平均を mZ と置いているので ◦ カーディナリティ = α_m * (m^2) * Z ◦ あれ, 前のページで導出した結果に α_m の積が余分にくっついてんじゃん ! ▪ これはどうも正規化するのに必要なものらしい ▪ 具体的には やっと戻ってきた
  13. まとめ • HyperLogLog とは • m 個のレジスタを持つデータ構造であり • 長大な入力が来ても, そのカーディナリティの推定を上記

    m 個だけで実現する • ちなみに, ここへきて突然言及しますが ◦ 各レジスタはだいたい 5B あれば十分らしく ◦ 相対誤差は 1.04/√m であり, これがどんなもんかというと ▪ m = 1 だと真値の2倍くらいの誤った値が出る ▪ m = 100 だと, 真値±10% くらいの範囲の推定値に収まる