Math.Netを使ってヒストグラムを作る

#はじめに
ヒストグラムを作る方法を記載します。
Math.Netを使ってデータからヒストグラムを作成し、
Chartコントロールで棒グラフ表示します。

#Math.Net
Math.Netは.NET開発者向け数学ライブラリです。
VisualStudioの参照設定で”Math.Net Numerics”を追加してください。

##ヒストグラムの作り方
MathNet.Numerics.Statistics.Histogramクラスを使います。
コンストラクタにデータ、Bucket数、上限値、下限値を指定します。
Bucketとはヒストグラムを棒グラフにしたときの1つの棒に対応するものです。

```csharp
int nBuckets = 10;
Histogram hist = new Histogram(data, nBuckets, -50 /* lower */, 50 /* upper */);
```

Bucket数、上限値、下限値からヒストグラムの度数をカウントする区間が決まります。
区間幅は (upper - lower) / Bucket数 となります。
例えば、upper = 50, lower = -50, Bucket数 = 10とすると、 区間幅は (50 - (-50) / 10) = 10となります。
各Bucketは (-50,-40], (-40,-30], .... , (40, 50]となります。
なお、"("は端を含まない区間記号、"]"は端を含む区間記号です。

各Bucketはindexで参照できます。indexの範囲は0~Bucket数-1です。

```csharp
for (int i = 0; i < nBuckets; i++)
{
    double mid = Math.Round((hist[i].UpperBound+hist[i].LowerBound)/2, 1);
    seriesColumn.Points.Add(new DataPoint(mid, hist[i].Count));
}
```

#例 正規乱数をヒストグラム表示する
![rei.JPG](https://qiita-image-store.s3.amazonaws.com/0/84205/b97e7ae3-556b-1859-4111-2bc217a25852.jpeg)

```csharp
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using MathNet.Numerics.Statistics;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private Random mRand;

        public Form1()
        {
            InitializeComponent();

            // clear
            chart1.Series.Clear();
            chart1.ChartAreas.Clear();
            chart1.Titles.Clear();

            Title title1 = new Title("Histgram");

            // series
            Series seriesColumn = new Series();
            seriesColumn.LegendText = "Histgram";
            seriesColumn.ChartType = SeriesChartType.Column;

            // 正規乱数を作る
            mRand = new Random(DateTime.Now.Millisecond);
            int nData = 10000;
            double[] data = new double[nData];
            for (int i = 0; i < nData; i++)
            {
                // Box-Muller法で一様乱数から正規乱数を作る
                data[i] = boxmuller(mRand, 0 /* average */ , 10 /* sigma */);
            }

            // ヒストグラムを作る
            int nBuckets = 10;
            Histogram hist = new Histogram(data, nBuckets, -50 /* lower */, 50 /* upper */);

            for (int i = 0; i < nBuckets; i++)
            {
                double mid = Math.Round((hist[i].UpperBound+hist[i].LowerBound)/2, 1);
                seriesColumn.Points.Add(new DataPoint(mid, hist[i].Count));
            }

            // chartarea
            ChartArea area1 = new ChartArea();
            area1.AxisX.Title = "Value";
            area1.AxisY.Title = "Frequency";

            chart1.Titles.Add(title1);
            chart1.ChartAreas.Add(area1);
            chart1.Series.Add(seriesColumn);
        }

        private double boxmuller(Random rdm, double ave, double sigma)
        {
            double r1 = rdm.NextDouble();
            double r2 = rdm.NextDouble();
            double std = Math.Sqrt(-2.0 * Math.Log(r1)) * Math.Sin(2.0 * Math.PI * r2);
            return ave + std * sigma;
        }
    }
}
```