LoginSignup
4
5

More than 5 years have passed since last update.

Python, matplotlibにより対数正規確率プロットを行う

Last updated at Posted at 2016-09-11

はじめに

報告書に以下のようなデータが記載されている。

Non-exceedance
probbility
Return period
(years)
Peak discharge
(m3/s)
0.50 2 950
0.80 5 1650
0.90 10 2190
0.95 20 2780
0.98 50 3610
0.99 100 4330
0.995 200 5090
0.998 500 6190
0.999 1000 7090

Note: based on 2-parameter lognormal distribution.

確率洪水流量は2変数対数正規分布で求めているようだ。
このデータを用いて、以下のことを行ってみる事にする。

  • 10000年確率洪水流量を推定する
  • 2変数対数正規分布に従っているか確認する

データに対して外挿することになるが、限られた情報の中で、勘で数字を出しましたというよりはマシであろう。まあ、プログラムの練習なので、統計的な厳密さには目をつぶることにして欲しい。

検討の流れ

回帰分析の準備

回帰分析の準備として,標準正規分布における非超過確率に対応するパーセント点,および流量の常用対数値を計算する.

ppp=norm.ppf(Pin, loc=0, scale=1)
qqq=np.log10(Qin)

回帰分析

次に目的変数を流量の対数値,説明変数を非超過確率のパーセント点として線形回帰を行ない、10000年確率に相当する洪水流量を推定する

scipy: optimize.leastsqを用いた線形回帰による回帰係数,相関係数の算出

parameter0 = [0.0,0.0]
result = optimize.leastsq(func,parameter0,args=(ppp,qqq))
aa=result[0][0]
bb=result[0][1]
rr=np.corrcoef(ppp,qqq)

optimize.leastsqのための関数(イコール0となる形式で表現する)

def func(parameter,x,y):
    a = parameter[0]
    b = parameter[1]
    residual = y-(a*x+b)
    return residual

回帰結果を用いた1000年確率の推定

pp=0.9999
xq=norm.ppf(pp, loc=0, scale=1)
Qpp=10**(aa*xq+bb)

対数正規確率紙へのプロット

対数正規分布に従っているかどうかは、対数正規確率紙にプロットし、確認する。ここでは、グラフの横軸に洪水流量(対数値)、縦軸に確率値をプロットする。このため、デフォルトの軸目盛りは削除し、横軸、縦軸とも独自に設定する。

軸目盛りおよび目盛り線の削除

plt.tick_params(labelbottom='off')
plt.tick_params(labelleft='off')
plt.tick_params(which='both', width=0)

グラフはpng画像として保存するが、Qiitaなどに貼ることを考慮して、余白を削除しておく。

plt.savefig('fig_flood_p.png', bbox_inches="tight", pad_inches=0.2)

プログラム

py_qq.py
import numpy as np
from scipy.stats import norm # normal distribution
from scipy import optimize
import matplotlib.pyplot as plt


# function for optimize.leastsq
def func(parameter,x,y):
    a = parameter[0]
    b = parameter[1]
    residual = y-(a*x+b)
    return residual

#==============================
# data analysis
#==============================
# flood discharge data
Qin=np.array([950,1650,2190,2780,3610,4330,5090,6190,7090])
# non-exceedance probability data
Pin=np.array([0.50,0.80,0.90,0.95,0.98,0.99,0.995,0.998,0.999])

ppp=norm.ppf(Pin, loc=0, scale=1)
qqq=np.log10(Qin)

# least square method
parameter0 = [0.0,0.0]
result = optimize.leastsq(func,parameter0,args=(ppp,qqq))
aa=result[0][0]
bb=result[0][1]
rr=np.corrcoef(ppp,qqq)

# estimation of 10,000 years return period flood
pp=0.9999
xq=norm.ppf(pp, loc=0, scale=1)
Qpp=10**(aa*xq+bb)

print('log10(Q) = a * x + b')
print('a={aa:10.6f} b={bb:10.6f} r={rr[0][1]:10.6f}'.format(**locals()))
print('Q={Qpp:10.3f} (pp={pp:0.4f})'.format(**locals()))


#==============================
# plot by matplotlib
#==============================
fig = plt.figure(figsize=(7,8))
xmin=np.log10(100)
xmax=np.log10(20000)
ymin=norm.ppf(0.0001, loc=0, scale=1)
ymax=norm.ppf(0.9999, loc=0, scale=1)
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
plt.tick_params(labelbottom='off')
plt.tick_params(labelleft='off')
plt.tick_params(which='both', width=0)

# data plot
plt.plot(qqq,ppp,'o')
# straight line by regression analysis
plt.plot([xmin, xmax], [(xmin-bb)/aa, (xmax-bb)/aa], color='k', linestyle='-', linewidth=1)

# setting of x-y axes
_dy=np.array([0.0001,0.001,0.01,0.1,0.5,0.9,0.99,0.999,0.9999])
dy=norm.ppf(_dy, loc=0, scale=1)
plt.hlines(dy, xmin, xmax, color='grey')
_dx=np.array([100,200,300,400,500,600,700,800,900,1000,2000,3000,4000,5000,6000,7000,8000,9000,10000,20000])
dx=np.log10(_dx)
plt.vlines(dx, ymin, ymax, color='grey')
fs=16
for i in range(2,5):
    plt.text(float(i), ymin-0.1, str(10**i), ha = 'center', va = 'top', fontsize=fs)
for i in range(0,9):
    plt.text(xmin-0.01, dy[i], str(_dy[i]), ha = 'right', va = 'center', fontsize=fs)
plt.text(0.5*(xmin+xmax), ymin-0.5, 'Flood discharge (m$^3$/s)', ha = 'center', va = 'center', fontsize=fs)
plt.text(xmin-0.25,0.5*(ymin+ymax),'Non-exceedance probability', ha = 'center', va = 'center', fontsize=fs, rotation=90)

# image saving and image showing
plt.savefig('fig_flood_p.png', bbox_inches="tight", pad_inches=0.2)
plt.show()

出力結果

$ python3 py_qq.py
log10(Q) = a * x + b
a=  0.282460 b=  2.978647 r=  0.999996
Q= 10693.521 (pp=0.9999)

fig_flood_p.png

参考サイト

Scipyの統計関数
http://kaisk.hatenadiary.com/entry/2015/02/17/192955

Scipyによる線形回帰事例
http://www2.kaiyodai.ac.jp/~kentaro/materials/new_HP/python/15fit_data3.html

matplotlibで画像の余白を削除する
https://mzmttks.blogspot.my/2012/01/pylab-2.html

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5