Python ヒストグラムの重ね合わせ

'22/05/03更新:ヒストグラムにしたデータを度数分布表へcsvに出力するコードを追記しました。
 本記事では、下図のように2つのデータを重ね合わせる雛形コードを載せました。半透明で表示することで、それぞれの分布が見易くなります。

さらに、下図のように度数分布表をcsvファイルへ出力する仕様です。

 次のように、階級数は引数binsで指定できます。そして、引数rangeを指定することで2つデータ群の階級幅を揃えることができます。

plt.hist(data, alpha = 0.5, bins = my_class_size, range = (my_min, my_max), label = 'A')

■本プログラム

#!/usr/bin/env python
# coding: utf-8

# In[1]:


import numpy as np
import pandas as pd
import math
import matplotlib.pyplot as plt
import japanize_matplotlib
plt.rcParams['font.size'] = 18 # グラフの基本フォントサイズの設定

# 正規分布でデータ1の生成
data1_np = np.random.normal(
    loc = 5, # 平均
    scale = 1.1, # 標準偏差 sigma
    size = 1100, # 出力配列のサイズ(タプルも可)
)
min1 = min(data1_np)
max1 = max(data1_np)
data1_size = len(data1_np)
print(min1, max1, data1_size)


# In[2]:


# 正規分布でデータ2の生成。データ1より、平均値が高くてばらつき小。
data2_np = np.random.normal(
    loc = 6, # 平均
    scale = 0.7, # 標準偏差 sigma
    size = 1000, # 出力配列のサイズ(タプルも可)
)
min2 = min(data2_np)
max2 = max(data2_np)
data2_size = len(data2_np)
print(min2, max2, data2_size)


# In[3]:


# 全データ区間の最小値と最大値を取得
if min1 <= min2:
    my_min = min1 # データ1の最小値を最小値とする
else:
    my_min = min2 # データ2の最小値を最小値とする
    
if max1 >= max2:
    my_max = max1 # データ1の最大値を最大値とする
else:
    my_max = max2 # データ2の最大値を最大値とする
print(my_min, my_max)


# In[4]:


# データ1と2で、データ数が大きい方をデータ数とする
if data1_size >= data2_size:
    N = data1_size
else:
    N = data2_size
print(N)


# In[5]:


# スタージェスの公式より
# 階級数を決める
my_class_size = int(1 + math.log2(N))
print('my_class_size', my_class_size)

# 階級幅(グラフ化には不要)
my_class_width = (my_max - my_min) / my_class_size
print('my_class_width', my_class_width)


# In[6]:


x_name = '寸法出来栄え'
y_name = '個数'
legend_name = '装置'

plt.hist(data1_np, alpha = 0.5, bins = my_class_size, range = (my_min, my_max), label = 'A')
plt.hist(data2_np, alpha = 0.5, bins = my_class_size, range = (my_min, my_max), label = 'B')
plt.xlabel(x_name)
plt.ylabel(y_name)
plt.legend(bbox_to_anchor = (1.3, 1), title = legend_name)
plt.grid()
#plt.xlim(0, 10)
#plt.savefig('histogram.jpg')
plt.show()


# In[7]:


# ヒストグラムの数値データを取得する関数
def extract_hist_data_func(DATA, CLASS_SIZE, MIN, MAX, FILE_NAME):
    # 階級幅
    class_width = (MAX - MIN) / CLASS_SIZE
    
    # 階級
    bins = np.arange(MIN, MAX + class_width, class_width)

    # 階級値
    class_value = (bins[1:] + bins[:-1]) / 2
    
    # 度数
    hist = np.histogram(DATA, bins)[0]
    
    # 階級の範囲
    class_name = [f'{bins[i]}以上{bins[i+1]}未満' for i in range(hist.size)]

    # 累積和
    cumsum = hist.cumsum()

    # 相対度数
    relative_hist = hist / cumsum[-1]

    # 累積相対度数
    cumsum_relative_hist = cumsum / cumsum[-1]

    ###
    # 列データをリストで作成
    column_data_list = list(zip(
    class_name, # 1. 階級の範囲
    class_value, # 2. 階級値
    hist, # 3. 度数
    cumsum, # 4. 累積和
    relative_hist, # 5. 相対度数
    cumsum_relative_hist, # 6. 累積相対度数
    ))

    # pandasデータフレームを作成
    df_buf = pd.DataFrame(column_data_list,
                  columns = ['階級', '階級値', '度数', '累積和', '相対度数', '累積相対度数'])

    # インデックスを1から振り直す
    df_buf.index = np.arange(1, len(df_buf) + 1)

    # csvファイルに保存
    df_buf.to_csv(FILE_NAME + '.csv', encoding = 'utf_8_sig')

    
# 作成したヒストグラムデータを抽出する関数を実行
extract_hist_data_func(data1_np, my_class_size, my_min, my_max, 'データ1')
extract_hist_data_func(data2_np, my_class_size, my_min, my_max, 'データ2')

以上

<広告>