как выбрать наилучшее непрерывное распределение из двух тестов на соответствие?

Я изучил вопрос Наиболее подходящий дистрибутив графики и выяснили, что в представленных ответах использовался критерий Колмогорова-Смирнова для поиска наилучшего распределения. Я также узнал, что существует тест Андерсона-Дарлинга, который также используется для получения наилучшего распределения. Итак, у меня есть несколько вопросов:

Вопрос 1:

Если у меня есть данные и я передаю их через гистограмму NumPy, какие параметры я должен использовать и какой результат я должен ввести в распределение?

def get_hist(data, data_size):
#### General code:
bins_formulas = ['auto', 'fd', 'scott', 'rice', 'sturges', 'doane', 'sqrt']
# bins = np.histogram_bin_edges(a=data, bins='scott')
# bins = np.histogram_bin_edges(a=data, bins='auto')
bins = np.histogram_bin_edges(a=data, bins='fd')
# print('Bin value = ', bins)

# Obtaining the histogram of data:
# Hist, bin_edges = histogram(a=data, bins=bins, range=np.linspace(start=np.min(data),end=np.max(data),size=data_size), density=True)
# Hist, bin_edges = histogram(a=data, range=np.linspace(np.min(data), np.max(data), data_size), density=True)
# Hist, bin_edges = histogram(a=data, bins=bins, density=True)
# Hist, bin_edges = histogram(a=data, bins=bins, range=(min(data), max(data)), normed=True, density=True)
# Hist, bin_edges = histogram(a=data, density=True)
Hist, bin_edges = histogram(a=data, range=(min(data), max(data)), density=True)
return Hist

Вопрос 2:

Если я хочу объединить оба теста, как я могу это сделать? какие параметры лучше всего использовать для поиска наилучшего распределения? Вот моя попытка объединить оба теста.

from statsmodels.stats.diagnostic import anderson_statistic as adtest
def get_best_distribution(data):
    dist_names = ['alpha', 'anglit', 'arcsine', 'beta', 'betaprime', 'bradford', 'burr', 'cauchy', 'chi', 'chi2', 'cosine', 'dgamma', 'dweibull', 'erlang', 'expon', 'exponweib', 'exponpow', 'f', 'fatiguelife', 'fisk', 'foldcauchy', 'foldnorm', 'frechet_r', 'frechet_l', 'genlogistic', 'genpareto', 'genexpon', 'genextreme', 'gausshyper', 'gamma', 'gengamma', 'genhalflogistic', 'gilbrat',  'gompertz', 'gumbel_r', 'gumbel_l', 'halfcauchy', 'halflogistic', 'halfnorm', 'hypsecant', 'invgamma', 'invgauss', 'invweibull', 'johnsonsb', 'johnsonsu', 'ksone', 'kstwobign', 'laplace', 'logistic', 'loggamma', 'loglaplace', 'lognorm', 'lomax', 'maxwell', 'mielke', 'moyal', 'nakagami', 'ncx2', 'ncf', 'nct', 'norm', 'pareto', 'pearson3', 'powerlaw', 'powerlognorm', 'powernorm', 'rdist', 'reciprocal', 'rayleigh', 'rice', 'recipinvgauss', 'semicircular', 't', 'triang', 'truncexpon', 'truncnorm', 'tukeylambda', 'uniform', 'vonmises', 'wald', 'weibull_min', 'weibull_max', 'wrapcauchy']
    dist_ks_results = []
    dist_ad_results = []
    params = {}
    for dist_name in dist_names:
        dist = getattr(st, dist_name)
        param = dist.fit(data)
        params[dist_name] = param

        # Applying the Kolmogorov-Smirnov test
        D_ks, p_ks = st.kstest(data, dist_name, args=param)
        print("Kolmogorov-Smirnov test Statistics value for " + dist_name + " = " + str(D_ks))
        # print("p value for " + dist_name + " = " + str(p_ks))
        dist_ks_results.append((dist_name, p_ks))

        # Applying the Anderson-Darling test:
        D_ad = adtest(x=data, dist=dist, fit=False, params=param)
        print("Anderson-Darling test Statistics value for " + dist_name + " = " + str(D_ad))
        dist_ad_results.append((dist_name, D_ad))

        print(dist_ks_results)
        print(dist_ad_results)

        for D in range (len(dist_ks_results)):
           KS_D = dist_ks_results[D][1]
           AD_D = dist_ad_results[D][1]
           if KS_D < 0.25 and AD_D < 0.05:
                best_ks_D = KS_D
                best_ad_D = AD_D
                if dist_ks_results[D][1] == best_ks_D:
                   best_ks_dist = dist_ks_results[D][0]
                if dist_ad_results[D][1] == best_ad_D:
                   best_ad_dist = dist_ad_results[D][0]

            print(best_ks_D)
            print(best_ad_D)
            print(best_ks_dist)
            print(best_ad_dist)

            print('\n################################ Kolmogorov-Smirnov test parameters #####################################')
            print("Best fitting distribution (KS test): " + str(best_ks_dist))
            print("Best test Statistics value (KS test): " + str(best_ks_D))
            print("Parameters for the best fit (KS test): " + str(params[best_ks_dist])
            print('################################################################################\n')
            print('################################ Anderson-Darling test parameters #########################################')
            print("Best fitting distribution (AD test): " + str(best_ad_dist))
            print("Best test Statistics value (AD test): " + str(best_ad_D))
            print("Parameters for the best fit (AD test): " + str(params[best_ad_dist]))
            print('################################################################################\n')

Вопрос 3:

Как я могу получить p-значение для теста Андерсона-Дарлинга?

Вопрос 4:

Скажем, мне удалось получить наиболее подходящее распределение, как можно ранжировать распределения на основе тестов? как на фото ниже.

Тесты соответствия с ранжированием

Изменить 1

Я не уверен, но является ли normal_ad из статистической модели общим тестом Андерсона-Дарлинга для любого непрерывного распределения вероятностей? если это так, я хотел бы выбрать дистрибутив, общий для обоих тестов. Если я выполню те же шаги, что и в вопросе 1, будет ли это правильным подходом? Кроме того, скажем, если я хочу найти самое высокое p-значение, которое является общим для обоих тестов, как я могу извлечь общее имя распределения с p-значениями?

def get_best_distribution(data):
dist_names = ['beta', 'bradford', 'burr', 'cauchy', 'chi', 'chi2', 'erlang', 'expon', 'f', 'fatiguelife', 'fisk', 'gamma', 'genlogistic', 'genpareto', 'invgauss', 'johnsonsb', 'johnsonsu', 'laplace', 'logistic', 'loggamma', 'loglaplace', 'lognorm', 'maxwell', 'mielke', 'norm', 'pareto', 'reciprocal', 'rayleigh', 't', 'triang', 'uniform', 'weibull_min', 'weibull_max']
dist_ks_results = []
dist_ad_results = []
params = {}
for dist_name in dist_names:
    dist = getattr(st, dist_name)
    param = dist.fit(data)
    params[dist_name] = param

    # Applying the Kolmogorov-Smirnov test
    D_ks, p_ks = st.kstest(data, dist_name, args=param)
    print("Kolmogorov-Smirnov test Statistics value for " + dist_name + " = " + str(D_ks))
    print("p value (KS test) for " + dist_name + " = " + str(p_ks))
    dist_ks_results.append((dist_name, p_ks))

    # Applying the Anderson-Darling test:
    D_ad, p_ad = adnormtest(x=data, axis=0)
    print("Anderson-Darling test Statistics value for " + dist_name + " = " + str(D_ad))
    print("p value (AD test) for " + dist_name + " = " + str(p_ad))
    dist_ad_results.append((dist_name, p_ad))

# select the best fitted distribution:
best_ks_dist, best_ks_p = (max(dist_ks_results, key=lambda item: item[1]))
best_ad_dist, best_ad_p = (max(dist_ad_results, key=lambda item: item[1]))

print('\n################################ Kolmogorov-Smirnov test parameters #####################################')
print("Best fitting distribution (KS test) :" + str(best_ks_dist))
print("Best p value (KS test) :" + str(best_ks_p))
print("Parameters for the best fit (KS test) :" + str(params[best_ks_dist]))
print('###########################################################################################################\n')
print('################################ Anderson-Darling test parameters #########################################')
print("Best fitting distribution (AD test) :" + str(best_ad_dist))
print("Best p value (AD test) :" + str(best_ad_p))
print("Parameters for the best fit (AD test) :" + str(params[best_ad_dist]))
print('###########################################################################################################\n')
if best_ks_dist == best_ad_dist:
    best_common_dist = best_ks_dist
    print('##################################### Both test parameters ############################################')
    print("Best fitting distribution (Both test) :" + str(best_common_dist))
    print("Best p value (KS test) :" + str(best_ks_p))
    print("Best p value (AD test) :" + str(best_ad_p))
    print("Parameters for the best fit (Both test) :" + str(params[best_common_dist]))
    print('###########################################################################################################\n')
    return best_common_dist, best_ks_p, params[best_common_dist]

Вопрос 5:

Поправьте меня, если я ошибаюсь при реализации теста соответствия, полученное значение p используется для проверки того, соответствуют ли данные значения какому-либо из упомянутых распределений. Таким образом, максимальное значение p-значения означает, что p-значение лежит ниже значимого уровня %5, поэтому, например, гамма-распределение соответствует данным. Я прав или не понял основной концепции теста Goodness-to-Fit?


person WDpad159    schedule 30.04.2020    source источник


Ответы (2)


Вопрос 3 легко решить с помощью OpenTURNS. Обычно я ранжирую распределения с помощью байесовского информационного критерия, потому что он позволяет считать лучшими распределения с меньшим количеством параметров.

В следующем примере я создаю гауссово распределение и генерирую на его основе выборку. Затем я вычисляю оценки BIC с помощью функции FittingTest.BIC для 30 дистрибутивов в библиотеке. Затем я использую функцию np.argsort, чтобы получить отсортированные индексы и распечатать результаты.

import openturns as ot
import numpy as np
# Generate a sample
distribution = ot.Normal()
sample = distribution.getSample(100)
tested_factories = ot.DistributionFactory.GetContinuousUniVariateFactories()
nbmax = len(tested_factories)
# Compute BIC scores
bic_scores = []
names = []
for i in range(nbmax):
    factory = tested_factories[i]
    names.append(factory.getImplementation().getClassName())
    try:
        fitted_dist, bic = ot.FittingTest.BIC(sample, factory)
    except:
        bic = np.inf
    bic_scores.append(bic)
# Sort the scores
indices = np.argsort(bic_scores)
# Print result
for i in range(nbmax):
    factory = tested_factories[i]
    name = factory.getImplementation().getClassName()
    print(names[indices[i]], ": ", i, bic_scores[indices[i]])

Это производит:

NormalFactory :  0 2.902476153791324
TruncatedNormalFactory :  1 2.9391403094910493
LogisticFactory :  2 2.945101831314491
LogNormalFactory :  3 2.948479498106734
StudentFactory :  4 2.9487326727806438
WeibullMaxFactory :  5 2.9506160993704653
WeibullMinFactory :  6 2.9646030668970464
TriangularFactory :  7 2.9683050343363897
TrapezoidalFactory :  8 2.970676202179786
BetaFactory :  9 3.033244379700322
RayleighFactory :  10 3.0511170157342207
LaplaceFactory :  11 3.0641174552986796
FrechetFactory :  12 3.1472260896504327
UniformFactory :  13 3.1551588725784927
GumbelFactory :  14 3.1928562445001263
HistogramFactory :  15 3.3881831435932748
GammaFactory :  16 3.3925823197940552
ExponentialFactory :  17 3.824030948338899
ArcsineFactory :  18 214.7536151046246
ChiFactory :  19 680.8835152447839
ChiSquareFactory :  20 683.6769102883109
FisherSnedecorFactory :  21 inf
LogUniformFactory :  22 inf
GeneralizedParetoFactory :  23 inf
RiceFactory :  24 inf
DirichletFactory :  25 inf
BurrFactory :  26 inf
InverseNormalFactory :  27 inf
MeixnerDistributionFactory :  28 inf
ParetoFactory :  29 inf

Есть дистрибутивы, которые не подходят для этой выборки. В этих дистрибутивах я устанавливаю BIC в INF и оборачиваю исключение в try/except.

person Michael Baudin    schedule 30.04.2020
comment
Спасибо за ваш ответ, я попробую. Я просто застрял с вопросом 1, 2 и редактирую 1. Вы прошли через эту ситуацию? - person WDpad159; 01.05.2020
comment
Извините, но у меня нет хорошей идеи по вопросу 1... за исключением того, что я не хотел бы делать это лично. - person Michael Baudin; 01.05.2020
comment
Можете ли вы сказать мне причину? - person WDpad159; 01.05.2020
comment
Кроме того, часто ли некоторые распределения имеют одинаковое значение p? если это так, что я могу сделать, чтобы иметь уникальные значения для каждого распределения? - person WDpad159; 01.05.2020
comment
Объединение двух методов для определения нового не является чем-то необычным. Но тест Колмогорова и тест Андерсона-Дарлинга имеют разные цели, поэтому я не могу найти способ их объединить. Кстати, для теста Колмогорова-Смирнова ваш способ использования теста, я думаю, неправильный: вы должны использовать тест Лиллифорса, как показано в stackoverflow.com/questions/57354430/ - person Michael Baudin; 01.05.2020
comment
У меня есть вопрос, скажите, что я использовал scipy для теста KS и получил статистику теста и значение p. Поправьте меня, если я ошибаюсь при реализации теста соответствия, полученное значение p используется для проверки того, соответствуют ли данные значения какому-либо из упомянутых распределений. Таким образом, максимальное значение p-значения означает, что p-значение лежит ниже значимого уровня %5, поэтому, например, гамма-распределение соответствует данным. Я прав или я не понял основной концепции теста Goodness-to-Fit? - person WDpad159; 14.05.2020

Вопрос 2. можно решить с помощью класса NormalityTest.AndersonDarlingNormal:

import openturns as ot
distribution = ot.Normal()
sample = distribution.getSample(100)
test_result = ot.NormalityTest.AndersonDarlingNormal(sample)
print(test_result.getPValue())

Это печатает:

0.8267360272974381

API задокументирован на странице справки функции, здесь пример и теория описана здесь.

person Michael Baudin    schedule 01.05.2020