Histgram関数の理解

### はじめに

Histgramは、numpyで計算してからplotする方法と、matplotlibで直接Plotする方法があります。（Matplotlibでも内部でnumpyを用いて計算している。）
matplotlibで直接Plotを行うには下記の1が参考になります。 ここでは、1の記事に従いnumpyで計算を行いその後Plotを行った覚えです。
ここでは、度数分布、相対度数分布、相対度数密度の計算とPlotを示します。

##### 参考
1. [matplotlibでヒストグラムの縦軸を相対度数（柱の高さの合計=1）や相対度数密度（ヒストグラム全体の面積=1）にする](https://qiita.com/kanedaq/items/1e7a0e52363224c08980)

2. [NumPyでヒストグラムを作るnp.histogram関数の使い方](https://deepage.net/features/numpy-histogram.html)

3. [pandasで度数分布表を自動で作る関数](https://www.self-study-blog.com/dokugaku/python-pandas-numpy-frequency-table/)


##### ヒストグラムの用語

階級：度数を集計するための 1つ1つ区間
階級数 : 階級の数
階級幅 : 区間の大きさを階級の幅
階級値 : その階級を代表する値（階級の真ん中の値）

度数 (Frequency)

相対度数 (Relative Frequency)
-> 相対度数 = 度数 / 度数の合計値

相対度数密度　(Density = relative frequency density)
-> 相対度数密度 = 相対度数 / 階級幅


度数密度 (frequency density)
-> 度数密度 = 度数 / 階級幅

#### 度数分布、相対度数分布、相対度数密度

```python
import matplotlib.pyplot as plt
import numpy as np
```

```python
# dataの作成
mu = 50
sg = 10
data = np.array([ np.random.normal(mu, sg) for i in range(10000) ])

print(f'Data length: {data.shape}, {len(data)}')
#>>>Data length: (10000,), 10000

plt.figure(figsize=(12, 6))
plt.subplot(1,2,1)
plt.plot(data)
plt.grid()

plt.subplot(1,2,2)
plt.plot(data.cumsum())
plt.title("cumsum")
plt.grid()
```
![output_2_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/014cee46-460d-400d-e445-c349724af03c.png)

#### 度数分布

```python
# Frequency example
print('Frequency example')

# Bins (階級数)
num_bins = 100

# Bins width　(階級幅)
bin_width = (max(data) - min(data)) / num_bins
print(f"Bin width: {bin_width:.3f}")

hist, bins = np.histogram(data, bins=num_bins) 

print(f'Bins length:{len(bins)}')
# binsの長さに注意　帰ってくるbinsの長さは指定したnum_bins+1
print(f'Histgram length: {len(hist)}')
print(f'Max cumsum: {hist.cumsum().max():.2f}')
print(f'Area: {np.sum(bin_width*hist):.2f}')

plt.figure(figsize=(12, 6))
plt.subplot(1,2,1)
plt.title("histgram")
plt.plot(bins[:-1],hist)
plt.grid()

plt.subplot(1,2,2)
plt.plot(bins[:-1],hist.cumsum())
plt.title("cumsum")
plt.grid()
```
Frequency example
    Bin width: 0.766
    Bins length:101
    Histgram length: 100
    Max cumsum: 10000.00
    Area: 7662.08

![output_3_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/25f9c8fc-bbbf-7884-5d6b-fd86960e195f.png)

#### 相対度数分布

```python
# Relative Frequency example
print('Relative Frequency example')

# Bins
num_bins = 100

# Bins width
bin_width = (max(data) - min(data)) / num_bins
print(f"Bin width: {bin_width:.3f}")

# weightsを指定することで各階級の重み付けを行う
weights = np.ones_like(data) / len(data)

print(f'weight length:{len(weights)}')

hist, bins = np.histogram(data, bins=num_bins, weights=weights) 

print(f'bins length:{len(bins)}')
print(f'histgram length: {len(hist)}')
print(f'Max cumsum: {hist.cumsum().max():.2f}')
print(f'Area: {np.sum(bin_width*hist):.2f}')
plt.figure(figsize=(12, 6))
plt.subplot(1,2,1)
plt.title("histgram")
plt.plot(bins[:-1],hist)
plt.grid()

plt.subplot(1,2,2)
plt.plot(bins[:-1],hist.cumsum())
plt.title("cumsum")
plt.grid()

# Note:
# 度数分布を求めて、度数累積和の最大値で規格化しても同じ
# hist, bins = np.histogram(data, bins=num_bins) 

# plt.figure(figsize=(12, 6))
# plt.subplot(1,2,1)
# plt.title("histgram")
# plt.plot(bins[:-1],hist/(max(hist.cumsum())))
# plt.grid()

# plt.subplot(1,2,2)
# plt.plot(bins[:-1],hist.cumsum()/(max(hist.cumsum())))
# plt.title("cumsum")
# plt.grid()
```

Relative Frequency example
Bin width: 0.766
weight length:10000
bins length:101
histgram length: 100
Max cumsum: 1.00
Area: 0.77

累積和の最大値が1になっている。

![output_5_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/b4c444a3-347a-bd61-e2c3-8831baaa0266.png)

```python
# 累積和で50%の位置の階級値を求めたい場合

def getNearestValue(list, num):
    """
    リストからある値に最も近い値を返却する関数
    Args:
        list (list or ndarray): 探索対象データ
        num (float): 対象値

    Returns:
        float:  対象値に最も近い値
    """
    # リスト要素と対象値の差分を計算し最小値のインデックスを取得
    idx = np.abs(np.asarray(list) - num).argmin()
    
    return idx

ind = getNearestValue(hist.cumsum(), 0.5)

print(f'Index :{ind}')
print(f'Bin : {bins[ind]}')

```

Index :52
Bin : 48.92290015560406

#### 相対度数密度

```python
# Density example

# Density (relative frequency density)
# -> Relative frequency density ->  relative frequency / bin_width

print('Density (relative frequency density) example')

# Bins
num_bins = 100

# Bins width
bin_width = (max(data) - min(data)) / num_bins
print(f"Bin width : {bin_width:.3f}")

weights = np.ones_like(data) / len(data)
print(f'weight length : {len(weights)}')


hist, bins = np.histogram(data, bins=num_bins, weights=weights, density=True) 

# weightsを指定しなくて同じ結果になる
# hist, bins = np.histogram(data, bins=num_bins, density=True) 

print(f'bins length : {len(bins)}')
print(f'histgram length : {len(hist)}')
print(f'Max cumsum : {hist.cumsum().max():.2f}')

# density = True :ヒストグラム全体の面積が1になる。
print(f'Area: {np.sum(bin_width*hist):.2f}')
plt.figure(figsize=(12, 6))
plt.subplot(1,2,1)
plt.title("histgram")
plt.plot(bins[:-1],hist)
plt.grid()

plt.subplot(1,2,2)
plt.plot(bins[:-1],hist.cumsum())
plt.title("cumsum")
plt.grid()
```
  Density (relative frequency density) example
    Bin width : 0.766
    weight length : 10000
    bins length : 101
    histgram length : 100
    Max cumsum : 1.31
    Area: 1.00

![output_7_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/744b5320-ae82-ea44-7ab1-28c842ce99f8.png)


#### 相対度数分布で範囲を変えた場合

```python
# Relative Frequency example. Range change

print('Range change  -Relative Frequency example- ')

# Bins
num_bins = 100

# Bins width
# bin_range =(min(data),max(data))
bin_range=(40,70)

bin_width = (max(bin_range) - min(bin_range)) / num_bins
print(f"Bin width: {bin_width:.3f}")

# weightsを指定することで各階級の重み付けを行う
weights = np.ones_like(data) / len(data)

print(f'weight length:{len(weights)}')

hist, bins = np.histogram(data, bins=num_bins, range=bin_range, weights=weights) 

print(f'bins length : {len(bins)}')
print(f'histgram length : {len(hist)}')
print(f'Max cumsum : {hist.cumsum().max():.2f}')
print(f'Area : {np.sum(bin_width*hist):.2f}')
plt.figure(figsize=(12, 6))
plt.subplot(1,2,1)
plt.title("histgram")
plt.plot(bins[:-1],hist)
plt.grid()

plt.subplot(1,2,2)
plt.plot(bins[:-1],hist.cumsum())
plt.title("cumsum")
plt.grid()
```
Range change  -Relative Frequency example- 
    Bin width: 0.300
    weight length:10000
    bins length:101
    histgram length: 100
    Max cumsum: 0.81
    Area: 0.24

![output_9_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165987/88d62b90-07f2-3819-b0f2-41e16d292504.png)