[リストへもどる]   [VBレスキュー(花ちゃん)]
一括表示

投稿時間:2006/02/18(Sat) 19:26
投稿者名:おじん
Eメール:
URL :
タイトル:
乱数について
場違いの質問かもしれませんがVBを使っているということで、、、
乱数発生で「正規分布」する数値を作ろうとしました。
数学の本を読んでいて「一様乱数の平均は正規分布になる」という
説明があり、下記のコードでテストをしてみましたが、見た目では
正規分布のようですが、19から51の範囲で指定したはずなのに
両端近辺の値が発生しないのです。何故なのかわかりません。
NomalRND(乱数発生)かCommand1(テスト)かのどちらかに間違いが
あるのですが。

'------------------------------------------------
Private Sub Command1_Click()
    Dim dat(), out%(99), n%, w!
    dat = NormalRND(19, 51, 400) 'この400を変えたら
    For n = 0 To 399             'ここも変える
        w = dat(n): out(w) = out(w) + 1
    Next n
    Me.Cls
    For n = 18 To 55
        Me.Print n, String(out(n), "-")
    Next n
End Sub
'------------------------------------------------
'      正規乱数の発生  
Private Function NormalRND( _
        ByVal low As Long, _
        ByVal up As Long, _
        ByVal m_max As Long) As Variant
'
'       low から up の間の数を m_max 個発生
'
    Dim r&, n&, m&, t(), x&
    Const n_cnt = 10    '一様乱数発生回数
    '        数値を大にするを分布が狭まる
    Randomize
    ReDim t(m_max - 1)   '正規乱数の回数
    Do Until n >= m_max - 1
        x = 0
    '   一様乱数の平均は正規分布になる
        For m = 1 To n_cnt
            r = Int((up - low + 1) * Rnd + low)
            x = x + r
        Next m
        x = Int(x / n_cnt) '平均をカウント
        t(n) = x
        n = n + 1
        DoEvents
    Loop
    NormalRND = t()      '正規乱数出力
End Function
'------------------------------------------------

投稿時間:2006/02/19(Sun) 06:44
投稿者名:おじん
Eメール:
URL :
タイトル:
Re: 原因が判明しました
原因はNormalRND関数の中にあると思います。
low から up の間の値の乱数を発生させているのですが
この「平均」の取り方では値は中心に集まってしまいます。
方法は考え中ですが工夫が必要のようです。
お迷惑、お騒がせいたしました。

投稿時間:2006/02/20(Mon) 10:26
投稿者名:ダンボ
URL :
タイトル:
Re^2: 原因が判明しました
> 原因はNormalRND関数の中にあると思います。

特に悪いとは思えないですが。
n_cnt = 1にすれば、「一様乱数の平均」ではなくて「一様乱数そのもの」の発生状況が簡易グラフで
見えます。ちゃんと19, 51近辺も出てますね。(しかし、400000個取ってもあまり一様でないような。。)

正規分布なのだから、両端が現れないのは当然(400個で3シグマ以上だと1個あるかないか)
むしろVBのRnd関数の一様度が悪いのではないかと疑います。

投稿時間:2006/02/20(Mon) 12:05
投稿者名:GOD
Eメール:
URL :
タイトル:
Re^3: 原因が判明しました
> 正規分布なのだから、両端が現れないのは当然(400個で3シグマ以上だと1個あるかないか)
> むしろVBのRnd関数の一様度が悪いのではないかと疑います。
>
乱数の精度はメルセンヌ・ツイスタというのがいいらしい。
hhttp://www001.upp.so-net.ne.jp/isaku/rand.html
VBのRnd関数も↑で書かれている事と同じ問題(Cのrand関数)を孕んでいるのでは?(未調査なので予測と
いうこ
とにして下さいm(_._)m)

投稿時間:2006/02/20(Mon) 14:09
投稿者名:ダンボ
URL :
タイトル:
Mersenne Twister法
GODさん、どうも。
Mersenne Twister法、Web上では随分評判が良いようですね。ただし検定結果まで載せたページは見つか
らなかった。
DLLはダウンロードできるのだけど、それほどのコードでもないので誰かVBに直してくれないかなあ?
(て普通は言いだしっぺの法則があるから言いたくは無いのだが)

投稿時間:2006/02/20(Mon) 15:23
投稿者名:おじん
Eメール:
URL :
タイトル:
Re: 御礼
GODさま、ダンボさま、ご指摘、ご指導ありがとうございます。
使用目的が「正規分布するテストデータの作成」にあったので
端っこのほうのデータもなくてはいけなかったのです。言い換えれば
標準偏差、平均は判明しています。
物の本には標準偏差、平均が分かっている場合の正規分布の乱数を発生
させる方法も書いてありましたがちんぷんかんぷんで、できそうな
「投稿方法(平均は正規分布になる)」をやってみたのです。
もう少し勉強します。ありがとうございました。

投稿時間:2006/02/20(Mon) 15:42
投稿者名:ダンボ
URL :
タイトル:
Re^2: 御礼
閉じようとしている、勉強しようとしているのに何ですが。。

> この「平均」の取り方では値は中心に集まってしまいます。

それが正に正規分布ってことで。

> 使用目的が「正規分布するテストデータの作成」にあったので
> 端っこのほうのデータもなくてはいけなかったのです。

正規分布では端っこのほうのデータは極端に少ないですよ。データ件数が400件では現れなくても当然。
「おじん さんのプログラムは基本的に正しいけれど、きれいな正規分布を求めるためにはきれいな
一様分布の乱数を基にしないと良くない」ということを言いたかったんですがね。

投稿時間:2006/02/20(Mon) 17:35
投稿者名:おじん
Eメール:
URL :
タイトル:
Re^3: 御礼
算数は少しどうにか、でも国語はだめです。
テストソース
>dat = NormalRND(19, 51, 400) '
の19,51は、それぞれ19から51の間できれいな(一見らしく)
正規分布様にサンプルデータを作りたい。端っこも含めて。
今の例では、平均(37)標準偏差(6)を想定するのであるから
下の値19を37-4*6=13に、また上の値51を37+4*6=61にすれば
良いのではと。
「勉強」とは、こんな試行錯誤をしてみようということでした。
VBのRNDのデータでは思わしくなく、山がひとつあるような
データが作りたい。正規分布という言葉を使ったことで皆さんに
ご迷惑をおかけしました。

投稿時間:2006/02/21(Tue) 10:45
投稿者名:ダンボ
URL :
タイトル:
モンテカルロではなく数式
> の19,51は、それぞれ19から51の間できれいな(一見らしく)
> 正規分布様にサンプルデータを作りたい。端っこも含めて。
> 今の例では、平均(37)標準偏差(6)を想定するのであるから

今ひとつ、話がかみ合わなかったですが。

「平均値と標準偏差が決まっているモデルに対して発生確率のサンプルデータをVBで作りたい」
ということなら、簡単なことです。正規分布の数式モデルは理論上
 F(x)=(1/sqrt(2*pi*標準偏差))exp(-(x-平均値)^2/2*標準偏差)
ですから、この式にfor x= 19 to 51 step 1を適用すれば作れますね。

平均値=37,標準偏差値=6
x=19の場合は0.000073804ですか。。。(手計算なので検算要)

母数400件ならば期待値は0.0295件でまず出現しない。
逆に1件出るためには13,549件以上サンプリングしないとおぼつかない。

投稿時間:2006/02/21(Tue) 11:10
投稿者名:おじん
Eメール:
URL :
タイトル:
Re: モンテカルロではなく数式
> > の19,51は、それぞれ19から51の間できれいな(一見らしく)
> 今ひとつ、話がかみ合わなかったですが。
おじんの数学と国語の知識レベルの所為です。

> ということなら、簡単なことです。正規分布の数式モデルは理論上
>  F(x)=(1/sqrt(2*pi*標準偏差))exp(-(x-平均値)^2/2*標準偏差)
> ですから、この式にfor x= 19 to 51 step 1を適用すれば作れますね。
こんな便利な式があるんですね。40数年前きっと習ったんでしょう。
利用させていただきます。
ありがとうございました。