在第一部分,我们用GEV分布对北京的年最高气温进行了拟合。在这一部分,我们将采用更多的分布进行拟合,并采用KS检验选择其中最优的一个。
读取数据
1 2 3 4 5 6 7 8 9 10 11 12 import pandas as pdimport numpy as npfrom plotnine.ggplot import *from plotnine.qplot import *from plotnine.geoms import *from plotnine.coords import *from plotnine.labels import *from plotnine.facets import *from plotnine.scales import *from plotnine.themes import *%matplotlib inline
1 2 3 4 5 6 data = pd.read_csv('CHM00054511.csv' ) print (data.head())print (data.dtypes)data.describe()
YYYY MM DD TMAX TMIN PRCP SNOW SNWD
0 1951 1 1 -3.8 -14.0 0.0 -9999.0 -9999.0
1 1951 1 2 -1.2 -10.0 0.5 -9999.0 -9999.0
2 1951 1 3 -4.1 -11.4 0.0 -9999.0 -9999.0
3 1951 1 4 -4.9 -10.1 1.2 -9999.0 -9999.0
4 1951 1 5 -6.6 -10.4 4.5 -9999.0 -9999.0
YYYY int64
MM int64
DD int64
TMAX float64
TMIN float64
PRCP float64
SNOW float64
SNWD float64
dtype: object
极值分析
1 2 import lmoments3from lmoments3 import distr
1 2 3 4 5 6 7 df = data.groupby('YYYY' , as_index=False ).TMAX.max () df = df[df.TMAX > 30 ] (ggplot(df) + aes('YYYY' , 'TMAX' ) + geom_point() )
1 lmoments3.lmom_ratios(df.TMAX, nmom=5 )
[37.27076923076924,
1.0495192307692305,
0.044338285016250305,
0.11816135435599627,
0.004419288498198655]
1 2 3 4 5 6 7 8 gevfit = distr.gev.lmom_fit(df.TMAX) expfit = distr.exp.lmom_fit(df.TMAX) gumfit = distr.gum.lmom_fit(df.TMAX) weifit = distr.wei.lmom_fit(df.TMAX) gpafit = distr.gpa.lmom_fit(df.TMAX) pe3fit = distr.pe3.lmom_fit(df.TMAX) gamfit = distr.gam.lmom_fit(df.TMAX) glofit = distr.glo.lmom_fit(df.TMAX)
得到不同分布下,在各个回归期的极端最高气温
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 T = np.arange(0.1 , 999.1 , 0.1 ) + 1 fitted_gev = distr.gev(**gevfit) gevST = fitted_gev.ppf(1.0 -1. /T) fitted_exp = distr.exp(**expfit) expST = fitted_exp.ppf(1.0 -1. /T) fitted_gum = distr.gum(**gumfit) gumST = fitted_gum.ppf(1.0 -1. /T) fitted_wei = distr.wei(**weifit) weiST = fitted_wei.ppf(1.0 -1. /T) fitted_gpa = distr.gpa(**gpafit) gpaST = fitted_gpa.ppf(1.0 -1. /T) fitted_pe3 = distr.pe3(**pe3fit) pe3ST = fitted_pe3.ppf(1.0 -1. /T) fitted_gam = distr.gam(**gamfit) gamST = fitted_gam.ppf(1.0 -1. /T) fitted_glo = distr.glo(**glofit) gloST = fitted_glo.ppf(1.0 -1. /T)
与经验分布比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 fitted_dict = { 'T' : T, 'gevST' : gevST, 'gumST' : gumST, 'expST' : expST, 'weiST' : weiST, 'gpaST' : gpaST, 'pe3ST' : pe3ST, 'gamST' : gamST, 'gloST' : gloST } fitted_df = pd.DataFrame(fitted_dict) fitted_df = pd.melt(fitted_df,id_vars='T' ) fitted_df.head()
T
variable
value
0
1.1
gevST
34.854597
1
1.2
gevST
35.454678
2
1.3
gevST
35.847042
3
1.4
gevST
36.144057
4
1.5
gevST
36.384550
1 2 3 4 5 p = (ggplot(fitted_df) + geom_line( aes(x='T' , y='value' , color='variable' )) + scale_x_log10() ) p
1 2 3 4 5 6 7 8 9 10 11 12 N = np.r_[1 :len (df.index)+1 ]*1.0 Nmax = max (N) y = sorted (df.TMAX, reverse=True ) empirical = pd.DataFrame({ 'T' :Nmax/N, 'empirical' :y }) empirical = pd.melt(empirical,id_vars='T' ) p = (p + geom_point(aes(x='T' , y='value' ,shape='variable' ), empirical,color='orange' ,show_legend=True ) + scale_color_discrete(name='fitted distribution' ) +scale_shape_discrete(name='empirical distribution' )) %matplotlib qt5 p
感慨:plotnine作图虽然漂亮,但是在操纵性上还好是matplotlib更顺手一些。
KS检验选择最优的分布
KS检验简介
通常,采用假设检验的方法选择最优分布,在这里我们使用柯尔莫哥洛夫-斯米尔诺夫检验(Колмогоров-Смирнов检验,kolmogorov-smirnov test(K-S test)。KS检验是基于累积概率分布函数,用于检验两个检验分布是否不同或一个经验分布与另一个理想分布是否不同,在Python中可以在scipy.stats.ks_2samp (https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.ks_2samp.html )中找到。
如上所述,KS统计量用来量化样本的经验分布函数与参考分布的累积分布函数之间或两个样本的经验分布函数之间的距离。该统计量的零分布是在零假设下计算的,即假设从参考分布中抽取样本(在单样本情况下)或样本是从同一分布中抽取的(在双样本情况下)。在每种情况下,在零假设下考虑的分布是连续分布,但在其他方面不受限制。
双样本K-S检验是用于比较两个样本的最有用和一般的非参数方法之一,因为它对两个样本的经验累积分布函数的位置和形状的差异敏感。KS检验也可以用来做来拟合优度检验(serve as a goodness of fit test)。
双样本K-S检验
假定有分别来自两个独立总体的两个样本,想要检验它们总体分布相同(即零假设)。
参数X,Y,两个由样本观测值组成的1维数据向量,数据的长度可以不同;
输出K-S统计量或者p-value,如果K-S统计量很小或者p-value很大,那么不能拒绝原假设。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 from scipy import statsN = np.r_[1 :len (df.index)+1 ]*1.0 Nmax = max (N) P0 = (N-1 )/Nmax P = np.delete(P0,0 ) obs = sorted (df.TMAX) gevSTo = fitted_gev.ppf(P) expSTo = fitted_exp.ppf(P) gumSTo = fitted_gum.ppf(P) weiSTo = fitted_wei.ppf(P) gpaSTo = fitted_gpa.ppf(P) pe3STo = fitted_pe3.ppf(P) gamSTo = fitted_gam.ppf(P) gloSTo = fitted_glo.ppf(P) ks = [('GEV' , stats.ks_2samp(obs, gevSTo)), ('EXP' , stats.ks_2samp(obs, expSTo)), ('GUM' , stats.ks_2samp(obs, gumSTo)), ('WEI' , stats.ks_2samp(obs, weiSTo)), ('GPA' , stats.ks_2samp(obs, gpaSTo)), ('PE3' , stats.ks_2samp(obs, pe3STo)), ('GAM' , stats.ks_2samp(obs, gamSTo)), ('GLO' , stats.ks_2samp(obs, gloSTo))] labels = ['Distribution' , 'KS (statistics, pvalue)' ] pd.DataFrame(ks, columns=labels)
Distribution
KS (statistics, pvalue)
0
GEV
(0.07211538461538464, 0.9945953083281929)
1
EXP
(0.1942307692307692, 0.15545877513797815)
2
GUM
(0.1317307692307692, 0.5996015052982722)
3
WEI
(0.07211538461538464, 0.9945953083281929)
4
GPA
(0.09639423076923076, 0.9115269503296325)
5
PE3
(0.07283653846153848, 0.9938564597747104)
6
GAM
(0.08774038461538464, 0.9568412059042808)
7
GLO
(0.08846153846153848, 0.9537725340776948)
可以看到,除了EXP和GUM外,其余的分布的值都在0.9以上,其中GEV(广义极值分布)具有最好的拟合优度(最小的ks统计量和最大的p值)。基于广义极值的结果重新作图(这次不想用pltonine了):
1 2 3 4 5 6 7 8 a = pd.DataFrame({ 'T' :1 /P,'value' :gevSTo[::-1 ]})(ggplot() + geom_point(aes(x='T' , y='value' ),color='orange' , data=empirical) + geom_line(aes(x='T' , y='value' ), data=a) + scale_x_log10(limits=[1 , 100 ]) )
1 2 3 4 import matplotlib.pyplot as pltplt.xscale('log' ) plt.plot(1 /P, gevSTo[::-1 ]) plt.scatter(Nmax/N, empirical.value, color = 'orangered' , facecolors='none' , label='Empirical' )
<matplotlib.collections.PathCollection at 0x1c11b0ffd0>
OrderedDict([('c', 0.20571249941146308),
('loc', 36.55285724490562),
('scale', 1.772333806935174)])
小结
在前一节工作的基础上,我们用多个分布进行了极值分析,并且利用KS检验选择了其中最好的一个。接下来,我们将采用Bootstrap采样方法估计选择的分布的置信区间。