正規分布の確率

  1. 平均と標準偏差
    1. 目的
      ここでは標準正規分布のグラフィック表示と指定した範囲の確率を計算します。
    2. 計算式
      標準正規分布は平均0、分散1の正規分布でその確率密度関数は

      f(x) = (1/sqrt(2π))exp(-x2)

      で与えられます。標準偏差sdの正規分布の確率密度関数は次のようになります。

        double gauss(double x,double sd){
          return (1.0/(Math.sqrt(2.0*Math.PI)*sd))*Math.exp(-x*x/(2.0*sd*sd));
        }
      ここではこのグラフを表示し、指定範囲の確率を数値積分法で計算します。

    3. 範囲の確率
       正規分布は連続関数ですから、特定の値に対する確率は意味がなく、「指定範囲の確率」の計算が必要です。下の図は、xが[0.0,1.0]の範囲を確率を表示しており、確率はこの範囲の確率密度関数とy=0(X軸)との面積(図の青色領域)に相当します。全範囲の確率は1になります。



       この関数の面積は、数学的には「積分」計算で行いますが、ここでは、プログラムで強引な面積計算を行います。

    4. 関数の面積計算
       矩形の面積は、幅*高さ で求められます。関数の面積は矩形ではありませんが、細かく区切ると
      台形に近似できます。


       上の図で 区間 [x,x+dh] の面積は、(y1+y2)*h/2 で計算できます。これをプログラムすると以下のようになります。ここでは、区間 [0,rx] の範囲の面積を求めています。関数の値y1は gauss(x,1.0) で、y2 は gauss(x+dh,1.0) で求めています。ここで、1.0は正規分布の分散です。
          double gs=0.0;
          double dh=0.01;
          for(x=0.0;x<rx;x=x+dh){
            gs = gs + (gauss(x,1.0)+gauss(x+dh,1.0))*dh/2.0;
          }
      この方法は、関数の変化が緩やかな場合は正確に計算できますが、変化が激しいときは誤差が大きくなります。

    5. スライダの利用
       範囲を指定する場合、数値入力は面倒です。ここでは、マウスのドラッグで値が設定できるスライダを利用してみましょう。スライダはGUI部品としては、Scrollbar(スクロールバー)クラスで定義されています。スクロールバーの値は、0から、setMaximum(n) で設定される最大値の範囲となります。また、バーの方向は縦と横の二つの方向があります。setOrientation(0) で横方向が指定できます。setBounds( ) は 他の部品と同様、バーの位置と大きさを指定します。

       private Scrollbar scrollbar1 = new Scrollbar();
       scrollbar1.setMaximum(50);
       scrollbar1.setOrientation(0);
       scrollbar1.setBounds(new Rectangle(27, 174, 94, 18));

      スクロールバーの値を変更したとき、呼び出す関数を設定します。ここでは、 scrollbar1_adjustmentValueChanged(e); を指定しています。

      scrollbar1.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
       public void adjustmentValueChanged(AdjustmentEvent e) {
        scrollbar1_adjustmentValueChanged(e);
       }
      });

       スライダの値は scrollbar1_adjustmentValueChanged(e); 関数の中で、e.getValue() で取得できます。ここでは、
        rx=(double)e.getValue()/10.0;
      で、スライダの値を10でわり、double型に変換しています。

    6. 色の指定とグラフ表示
       二項分布の確率密度関数をグラフ表示します。ここでは、x=-4.0から4.0までの範囲を 0.02 刻みで折れ線でつないで表示します。
       また、指定範囲を青色で塗りつぶします。このため、まず表示する色を指定します。表示色を青色に変更するには
       g.setColor(Color.blue);
      を呼び出します。任意の色に設定するには、new Color(0,100,255) のように、r,g,b の色の強度を 0..255 の範囲で指定します。この色で、指定範囲を棒線で塗りつぶします。表示間隔が 0.02 と異常に細かいのは塗りつぶしのためで、範囲を塗りつぶす必要がなければ、0.1くらいで十分です。
       
  2. プログラム
    1. 画面レイアウト
       部品としてスライダと結果の表示用ラベルを用意します。

    2. 処理の流れ
       スライダをドラッグすると、scrollbar1_adjustmentValueChanged() が呼び出され、ここで、スライダの値を読み取り、area() 関数で確率を計算し、表示します。

    3. 画面表示:paint()
       確率密度関数の表示と、指定範囲を青色で表示します。

    4. ソース
       
      import java.awt.*;
      import java.awt.event.*;
      import java.applet.*;
      
      /**
       * <p>タイトル: </p>
       * <p>説明: </p>
       * <p>著作権: Copyright (c) 2004</p>
       * <p>会社名: </p>
       * @author 未入力
       * @version 1.0
       */
      
      public class Applet1 extends Applet {
        private boolean isStandalone = false;
        double rx=0.0;
      
        private Scrollbar scrollbar1 = new Scrollbar();
        private Label pblabel = new Label();
        private Label xlabel = new Label();
        private Label label2 = new Label();
        private Label label3 = new Label();
        //引数値の取得
        public String getParameter(String key, String def) {
          return isStandalone ? System.getProperty(key, def) :
            (getParameter(key) != null ? getParameter(key) : def);
        }
      
        //アプレットのビルド
        public Applet1() {
        }
        //アプレットの初期化
        public void init() {
          try {
            jbInit();
          }
          catch(Exception e) {
            e.printStackTrace();
          }
        }
        //コンポーネントの初期化
        private void jbInit() throws Exception {
          this.setLayout(null);
          scrollbar1.setMaximum(50);
          scrollbar1.setOrientation(0);
          scrollbar1.setBounds(new Rectangle(27, 174, 94, 18));
          scrollbar1.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
            public void adjustmentValueChanged(AdjustmentEvent e) {
              scrollbar1_adjustmentValueChanged(e);
            }
          });
          pblabel.setText("0.0");
          pblabel.setBounds(new Rectangle(220, 172, 45, 20));
          xlabel.setText("0.0");
          xlabel.setBounds(new Rectangle(146, 172, 47, 20));
          label2.setText("x");
          label2.setBounds(new Rectangle(146, 157, 37, 20));
          label3.setText("確率");
          label3.setBounds(new Rectangle(217, 156, 53, 17));
          this.add(label3, null);
          this.add(label2, null);
          this.add(scrollbar1, null);
          this.add(xlabel, null);
          this.add(pblabel, null);
        }
        //アプレットの情報取得
        public String getAppletInfo() {
          return "アプレット情報";
        }
        //引数情報の取得
        public String[][] getParameterInfo() {
          return null;
        }
      
        public void paint(Graphics g){
          double x=0.0,y;
          int ox=20,oy=120;
          double px,py;
      
          px=-4.0;
          py=gauss(px,1.0);
          for(x=-4.0;x<4.0;x=x+0.02){
            y=gauss(x,1.0);
            g.drawLine((int)((px+4.0)*30.0)+ox,(int)(oy-py*200.0),
                       (int)((x+4.0)*30.0)+ox,(int)(oy-y*200.0));
            //範囲なら縦線表示
            if( x>0.0 && x<rx){
              g.setColor(Color.blue);
              g.drawLine((int)((x+4.0)*30.0)+ox,oy,
                         (int)((x+4.0)*30.0)+ox,(int)(oy-y*200.0));
              g.setColor(Color.black);
            }
            px=x;py=y;
          }
        }
      
        double gauss(double x,double sd){
          return (1.0/(Math.sqrt(2.0*Math.PI)*sd))*Math.exp(-x*x/(2.0*sd*sd));
        }
      
        double area(double rx){
          double x;
          double gs=0.0;
          double dh=0.01;
          for(x=0.0;x<rx;x=x+dh){
            gs = gs + (gauss(x,1.0)+gauss(x+dh,1.0))*dh/2.0;
          }
          //System.out.println("rx:"+rx+" area:"+gs);
          pblabel.setText(Double.toString(gs));
          xlabel.setText(Double.toString(rx));
          return gs;
        }
      
        void scrollbar1_adjustmentValueChanged(AdjustmentEvent e) {
          rx=(double)e.getValue()/10.0;
          area((double)rx);
          repaint();
        }
      
      }

    5. 実行
       スライダのつまみをドラッグします。範囲の確率が表示されます。正規分布表と比較して下さい。



  3. 演習
     
    1. 演習1
      プログラムのソースをファイルに保存し、コンパイル&実行をして下さい。また、計算される確率の値を正規分布表と比較して下さい。

    2. 演習2
       確率密度関数 gauss(double x,double sd) はsdに分散の値が設定できます。分散の値をスライダで変更し、確率密度関数を表示して下さい。