Zipf分布に従う乱数の生成方法

Zipf分布といえば,べき乗則でおなじみの分布です(http://en.wikipedia.org/wiki/Zipf%27s_law).一方,Zipf-MandelbrotはZipf分布を一般化したものだそうです(http://en.wikipedia.org/wiki/Zipf%E2%80%93Mandelbrot_law).


Zipf-MandelbrotのPDFは

f(x) = c / (x + b)^a

となるわけですが,今回はより単純な形式である,

f(x) = 1 / x

というPDFに従う乱数を生成する方法を説明します.


まず,CDFを求めてみます.ただし,PDFの積分

∫f(x) dx = ln(x) + C (Cは積分定数)

であるけれど,F(0) = 0なのでCDFは

F(x) = ln(x)

となります.


次に,F(x)の逆関数をもとめます.

y = ln(x)
e^y = x

より,

F^(-1) (x) = e^x

となります.


ここで,逆関数法(http://www.okada.jp.org/RWiki/index.php?%CD%F0%BF%F4Tips%C2%E7%C1%B4#j3f49d96)による乱数生成より,F^(-1) (x)に一様分布に従う乱数を渡せば,Zipf分布に従う乱数が得られます.ただし,実際には[0, 1)の範囲になるように正規化するので,e^x / e = e^(x - 1)を利用します.


Pythonの場合

def zipf():
    return math.e ** (random.random() - 1)


最大値を指定する場合

def zipf(max):
    return math.e ** (random.random() * math.log(max + 1.0)) - 1.0


ちなみに,f(x) = 1 / xという分布は,http://en.wikipedia.org/wiki/Zipf%27s_law#Related_lawsにあるように,英語版のWikipediaの単語分布と非常に近い分布となるらしいです.