Python(基本統計量の算出ツール)

今回はこちらのプログラム
基本統計量の算出
を元に、入力値から平均、分散、標準偏差を表示するGUIツールを作成した後、matplotlibライブラリを利用してヒストグラムやグラフを表示させるツールをプログラムしました。

まず、matplotlibライブラリがインストールされていない場合は、コマンドラインツールからpipコマンドでインストールしてください。

pip install matplotlib

平均、分散、標準偏差の計算については

  1. 入力値のリストを保持して、計算式から求める方法
  2. データ数、入力値の合計、入力値の2乗の合計を保持して求める方法

があります。計算だけの単純なものなので、それぞれのコードを紹介で乗せておきます。

from AppBase import *
from tkinter import font
import math

"""
xs=[*range(1,101)]
moment(xs,1) # 平均値
moment(xs,2,moment(xs,1)) # 分散
# 積率による分散の計算
moment(xs,2) - moment(xs,1)**2
"""

class Application(AppBase):
    def __init__(self, master=None):
        super().__init__(master)
        self.bind_all('<Delete>', self.reset)
        self._xs = []

    @staticmethod
    def moment(xs,m,u=0):
        return sum((x-u)**m for x in xs) / len(xs)

    def create_extra_widgets(self):
        f_table = tk.Frame(self)
        f_table.pack(expand=1, fill=tk.BOTH)
        self._tsv = tk.StringVar()        
        self._table = tk.Label(f_table,justify=tk.LEFT, anchor=tk.NW, textvariable=self._tsv)
        self._table.pack(expand=1, fill=tk.BOTH)
        f_result = tk.Frame(self,relief=tk.RIDGE, bd=4)
        f_result.pack(expand=1, fill=tk.BOTH)
        font1 = font.Font(family='Helvetica', size=15, weight='bold')
        self._a = tk.StringVar()
        self._ave = tk.Label(f_result, font=font1,justify=tk.LEFT, anchor=tk.NW, textvariable=self._a)
        self._ave.pack(side=tk.LEFT)
        self._b = tk.StringVar()
        self._var = tk.Label(f_result, font=font1,justify=tk.LEFT, anchor=tk.NW, textvariable=self._b)
        self._var.pack(side=tk.LEFT)
        self._c = tk.StringVar()
        self._dev = tk.Label(f_result, font=font1,justify=tk.LEFT, anchor=tk.NW, textvariable=self._c)
        self._dev.pack(side=tk.LEFT)
        self.init_table()

    def init_table(self):
        self._tsv.set("値を入力してEnterを押してください")
        self._a.set("")
        self._b.set("")
        self._c.set("")

    def set_table(self):
        self._tsv.set(" | ".join(f"{i+1}番目:{x}" for i,x in enumerate(self._xs)))

    def set_ave(self):
        self._a.set("平均値:%.4f" % Application.moment(self._xs,1))

    def set_var(self):
        self._b.set("分散:%.4f" % Application.moment(self._xs,2,Application.moment(self._xs,1)))

    def set_dev(self):
        self._c.set("標準偏差:%.4f" % math.sqrt(Application.moment(self._xs,2,Application.moment(self._xs,1))))

    def reset(self,event=None):
        self._xs.clear()
        self.init_table()
        self.display('')

    def on_enter(self, sv):
        s = sv.get()
        try:
            x = float(s)
            self.display(f'整数値の取得に成功しました\n--> {x}')
            self._xs.append(x)
            self.set_table()
            self.set_ave()
            self.set_dev()
            self.set_var()            
            sv.set('')
        except:
            self.display(f'数値に変換できません! {s}')

if __name__ == '__main__':
    app = Application()
    app.mainloop()

from AppBase import *
from tkinter import font
import math

class Application2(AppBase):
    def __init__(self, master=None):
        super().__init__(master)
        self.bind_all('<Delete>', self.reset)
        self.sum = 0
        self.sum2 = 0
        self.n = 0

    def create_extra_widgets(self):
        f_table = tk.Frame(self)
        f_table.pack(expand=1, fill=tk.BOTH)
        self._nsv = tk.StringVar()        
        self.l_n = tk.Label(f_table,justify=tk.LEFT, anchor=tk.NW, textvariable=self._nsv)
        self.l_n.pack(side=tk.LEFT)
        self._ssv = tk.StringVar()  
        self.l_s = tk.Label(f_table,justify=tk.LEFT, anchor=tk.NW, textvariable=self._ssv)
        self.l_s.pack(side=tk.LEFT)
        self._s2sv = tk.StringVar()
        self.l_s2 = tk.Label(f_table,justify=tk.LEFT, anchor=tk.NW, textvariable=self._s2sv)
        self.l_s2.pack(side=tk.LEFT)    
        f_result = tk.Frame(self,relief=tk.RIDGE, bd=4)
        f_result.pack(expand=1, fill=tk.BOTH)
        font1 = font.Font(family='Helvetica', size=15, weight='bold')
        self._a = tk.StringVar()
        self._ave = tk.Label(f_result, font=font1,justify=tk.LEFT, anchor=tk.NW, textvariable=self._a)
        self._ave.pack(side=tk.LEFT)
        self._b = tk.StringVar()
        self._var = tk.Label(f_result, font=font1,justify=tk.LEFT, anchor=tk.NW, textvariable=self._b)
        self._var.pack(side=tk.LEFT)
        self._c = tk.StringVar()
        self._dev = tk.Label(f_result, font=font1,justify=tk.LEFT, anchor=tk.NW, textvariable=self._c)
        self._dev.pack(side=tk.LEFT)

    def init_value(self):
        self._a.set("")
        self._b.set("")
        self._c.set("")

    def set_value(self):
        ave = self.sum / self.n
        var = self.sum2 / self.n - ave**2
        self._a.set("平均値:%.4f" % ave)
        self._b.set("分散:%.4f" % var)
        self._c.set("標準偏差:%.4f" % math.sqrt(var))
        self._nsv.set(f"{self.n}回目")
        self._ssv.set(f"合計:{self.sum}")
        self._s2sv.set(f"二乗合計:{self.sum2}")

    def reset(self,event=None):
        self.init_value()
        self.display('')

    def on_enter(self, sv):
        s = sv.get()
        try:
            x = float(s)
            self.display(f'整数値の取得に成功しました\n--> {x}')
            self.sum += x
            self.sum2 += x**2
            self.n += 1
            self.set_value()
            sv.set('')
        except:
            self.display(f'数値に変換できません! {s}')

if __name__ == '__main__':
    app = Application2()
    app.mainloop()

pylabモジュールで資料表示

matplotlibライブラリのpylabモジュールを使うと簡単にヒストグラムやグラフを作成することができます。

import pylab
# ヒストグラム作成
pylab.hist([1,1,2,2,2,3,4,5,5,5,6,6,6,6,6])
pylab.show()

import pylab
# グラフ作成
pylab.plot([1,2,3,6],[1,4,9,36])
pylab.show()

histメソッドの引数にデータリストを、plotメソッドの引数にx軸、y軸のデータリストを渡してshowメソッドを呼ぶだけで簡単に作成してくれます。

これを利用してcos関数や標準正規分布を表示させることも簡単です。

import pylab
import random
import math

# cosグラフ作成
xs=[x/100 for x in range(1000)]
ys=[math.cos(x) for x in xs]
pylab.plot(xs,ys)
pylab.show()

# 標準正規分布のヒストグラム
pylab.hist([random.gauss(0,1) for _ in range(10000)],bins=50)
pylab.show()

# 標準正規分布のグラフをplot
xp=[x/100 for x in range(-400,401)]
yp=[(1/2*math.pi*1)*math.exp(-(x-0)**2/2*1) for x in xp]
pylab.plot(xp,yp)
pylab.show()



random.gauss(0,1)
平均 mu=0、標準偏差 sigma=1で、randomモジュールのgaussメソッドによる乱数を生成してプロットすると標準正規分布する資料が得られます。

正規分布を含め、確率分布について詳しく知りたい人は以下参照
WebサービスのA/Bテストや機械学習でよく使う「確率分布」18種を解説

基本統計量の算出ツール

基本となるGUIツールにpylabモジュールでヒストグラムと正規分布すると仮定した場合のグラフ表示機能を追加したものです。

from AppBase import *
from tkinter import font
import math,pylab,random

"""
xs=[*range(1,101)]
moment(xs,1) # 平均値
moment(xs,2,moment(xs,1)) # 分散
# 積率による分散の計算
moment(xs,2) - moment(xs,1)**2
"""

class Application(AppBase):
    def __init__(self, master=None):
        super().__init__(master)
        self.bind_all('<Delete>', self.reset)
        self.bind_all('<s>', self.show)
        self.bind_all('<g>', self.gauss)
        self.bind_all('<p>', self.plot)
        self._xs = []

    @staticmethod
    def moment(xs,m,u=0):
        return sum((x-u)**m for x in xs) / len(xs)

    def create_extra_widgets(self):
        f_table = tk.Frame(self)
        f_table.pack(expand=1, fill=tk.BOTH)
        self._tsv = tk.StringVar()        
        self._table = tk.Label(f_table,justify=tk.LEFT, anchor=tk.NW, textvariable=self._tsv)
        self._table.pack(expand=1, fill=tk.BOTH)
        f_result = tk.Frame(self,relief=tk.RIDGE, bd=4)
        f_result.pack(expand=1, fill=tk.BOTH)
        font1 = font.Font(family='Helvetica', size=15, weight='bold')
        self._a = tk.StringVar()
        self._ave = tk.Label(f_result, font=font1,justify=tk.LEFT, anchor=tk.NW, textvariable=self._a)
        self._ave.pack(side=tk.LEFT)
        self._b = tk.StringVar()
        self._var = tk.Label(f_result, font=font1,justify=tk.LEFT, anchor=tk.NW, textvariable=self._b)
        self._var.pack(side=tk.LEFT)
        self._c = tk.StringVar()
        self._dev = tk.Label(f_result, font=font1,justify=tk.LEFT, anchor=tk.NW, textvariable=self._c)
        self._dev.pack(side=tk.LEFT)
        self.init_table()

    def init_table(self):
        self._tsv.set("値を入力してEnterを押してください")
        self._a.set("")
        self._b.set("")
        self._c.set("")

    def set_table(self):
        self._tsv.set(" | ".join(f"{i+1}番目:{x}" for i,x in enumerate(self._xs)))

    def set_ave(self):
        self.mu = Application.moment(self._xs,1)
        self._a.set("平均値:%.4f" % self.mu)

    def set_var(self):
        self.sigma2 = Application.moment(self._xs,2,Application.moment(self._xs,1))
        self._b.set("分散:%.4f" % self.sigma2)

    def set_dev(self):
        self.sigma = math.sqrt(self.sigma2)
        self._c.set("標準偏差:%.4f" % self.sigma)

    def reset(self,event=None):
        self._xs.clear()
        self.init_table()
        self.display('')

    def on_enter(self, sv):
        s = sv.get()
        try:
            x = float(s)
            self.display(f'整数値の取得に成功しました\n--> {x}')
            self._xs.append(x)
            self.set_table()
            self.set_ave()            
            self.set_var()
            self.set_dev()          
            sv.set('')
        except:
            self.display(f'数値に変換できません! {s}')

    def show(self,event=None):
        pylab.hist(self._xs)
        pylab.show()

    def gauss(self,event=None):
        pylab.hist([random.gauss(self.mu,self.sigma) for _ in range(10000)],bins=50)
        pylab.show()

    def plot(self,event=None):
        xs=[x/100 for x in range(-400,401)]
        ys=[(1/2*math.pi*self.sigma2)*math.exp(-(x-self.mu)**2/2*self.sigma2) for x in xs]
        pylab.plot(xs,ys)
        pylab.show()

if __name__ == '__main__':
    app = Application()
    app.mainloop()

データを入力後、キーボードのs,g,pに対応イベントを追加して、資料表示できるようにしています。

統計について興味のある方はmatplotlibライブラリのpylabモジュールを活用してみてください。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください