如何找到真实数据的概率分布和参数? (Python 3)
Posted
技术标签:
【中文标题】如何找到真实数据的概率分布和参数? (Python 3)【英文标题】:How to find probability distribution and parameters for real data? (Python 3) 【发布时间】:2016-09-26 01:12:21 【问题描述】:我有一个来自sklearn
的数据集,我绘制了load_diabetes.target
数据的分布(即load_diabetes.data
用于预测的回归值)。
我使用它是因为它具有最少数量的回归变量/属性sklearn.datasets
。
使用 Python 3,我怎样才能得到最接近分布的分布类型和参数?
我所知道的 target
值都是正数和偏斜的(正偏斜/右偏斜)。 . . Python中有没有办法提供一些分布,然后得到最适合target
数据/向量的方法?或者,根据给出的数据实际建议适合?这对于具有理论统计知识但很少有将其应用于“真实数据”经验的人来说将非常有用。
奖金 使用这种方法来确定“真实数据”的后验分布是否有意义?如果没有,为什么不呢?
from sklearn.datasets import load_diabetes
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()
import pandas as pd
#Get Data
data = load_diabetes()
X, y_ = data.data, data.target
#Organize Data
SR_y = pd.Series(y_, name="y_ (Target Vector Distribution)")
#Plot Data
fig, ax = plt.subplots()
sns.distplot(SR_y, bins=25, color="g", ax=ax)
plt.show()
【问题讨论】:
您可以对数据进行几次拟合,然后选择产生最小拟合误差的那个。 你的图中的kde曲线是你想要的函数吗? @Philip;为此,您会从这里获取分布:docs.scipy.org/doc/scipy/reference/stats.html 吗?挑选和选择哪些最适合?如果不知道样本分布的参数,如何检验拟合? @ZichenWang 不一定。最终,我会寻找以下分布之一:pymc-devs.github.io/pymc3/api.html 具有特定参数和拟合误差 这个answer shows all thescipy.stats
distributions available,也许你可以结合其中的一些来生成你想要的分布。
【参考方案1】:
使用这种方法
import scipy.stats as st
def get_best_distribution(data):
dist_names = ["norm", "exponweib", "weibull_max", "weibull_min", "pareto", "genextreme"]
dist_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, p = st.kstest(data, dist_name, args=param)
print("p value for "+dist_name+" = "+str(p))
dist_results.append((dist_name, p))
# select the best fitted distribution
best_dist, best_p = (max(dist_results, key=lambda item: item[1]))
# store the name of the best fit and its p value
print("Best fitting distribution: "+str(best_dist))
print("Best p value: "+ str(best_p))
print("Parameters for the best fit: "+ str(params[best_dist]))
return best_dist, best_p, params[best_dist]
【讨论】:
您能解释一下这种方法吗? 它是上面答案中代码的完整版本。他们为所有可能适合数据的分布创建了一个项目列表。然后他们使用 p 分数创建一个假设,以确定该分布与数据的匹配程度。具有最高 p 分数的内容被认为是最准确的。这是因为较高的 p 分数意味着假设最接近现实。 有没有办法让这段代码也尝试截断正态分布?我在数据集的列表中添加了“truncnorm”,但该函数始终返回 p 值 = 0。谢谢! 在这种方法中,您正在寻找最大 P 作为最佳方法。不应该是要选择的min(p)吗? 您好,感谢您采用这种方法。得到分布的参数后,如何从同一个分布中生成合成数据?有什么想法吗?【参考方案2】:据我所知,没有自动获取样本分布类型和参数的方法(因为推断样本的分布本身就是一个统计问题)。
在我看来,你能做的最好的就是:
(对于每个属性)
尝试将每个属性拟合到一个相当大的可能分布列表 (例如,有关 Scipy 的示例,请参阅 Fitting empirical distribution to theoretical ones with Scipy (Python)?)
评估您的所有适合度并选择最佳的。这可以通过在您的样本和拟合的每个分布之间执行 Kolmogorov-Smirnov 测试来完成(您再次在 Scipy 中有一个实现),然后选择一个最小化 D 的测试统计量(也就是样本和拟合)。
奖励:这是有道理的 - 因为您将在每个变量上构建模型,同时为每个变量选择合适的模型 - 尽管您的预测的好坏取决于您的数据质量和您的分布用于拟合。毕竟,您正在构建模型。
【讨论】:
如果您需要查看all thescipy.stats
distributions,请查看here。
但是如何区分单模态分布和多模态分布呢?例如,在这里 (imgur.com/a/NZKxxRv),如果足够大胆的话,我可以看到 3 种正态分布模式或仅一种模式。
本文概述了如何使用 Fitter 库来自动识别 scipy 的哪些分布最适合数据towardsdatascience.com/…【参考方案3】:
您可以使用该代码来拟合(根据最大可能性)您的数据的不同分布:
import matplotlib.pyplot as plt
import scipy
import scipy.stats
dist_names = ['gamma', 'beta', 'rayleigh', 'norm', 'pareto']
for dist_name in dist_names:
dist = getattr(scipy.stats, dist_name)
param = dist.fit(y)
# here's the parameters of your distribution, scale, location
你可以在此处查看有关如何使用获取的参数的示例 sn-p:Fitting empirical distribution to theoretical ones with Scipy (Python)?
然后,您可以选择具有最佳对数似然的分布(还有其他标准可以匹配“最佳”分布,例如贝叶斯后验概率、AIC、BIC 或 BICc 值,. ..)。
对于您的额外问题,我认为没有通用答案。如果你的数据集很重要,并且在与真实单词数据相同的条件下获得,你就可以做到。
【讨论】:
我实现了上面的代码,参数只显示了 3 个值。它们不应该等于 5 吗? 此外,在数据集不完整的情况下,使用期望最大化 (EM) 算法而不是传统的最大似然估计 (MLE) - 当存在一些未观察到或隐藏的变量时(它们被称为作为潜在变量)【参考方案4】:此代码也有效:
import pandas as pd
import numpy as np
import scipy
from scipy import stats
#Please write below the name of the statistical distributions that you would like to check.
#Full list is here: https://docs.scipy.org/doc/scipy/reference/stats.html
dist_names = ['weibull_min','norm','weibull_max','beta',
'invgauss','uniform','gamma','expon',
'lognorm','pearson3','triang']
#Read your data and set y_std to the column that you want to fit.
y_std=pd.read_csv('my_df.csv')
y_std=y_std['column_A']
#-------------------------------------------------
chi_square_statistics = []
size=len(y_std)
# 20 equi-distant bins of observed Data
percentile_bins = np.linspace(0,100,20)
percentile_cutoffs = np.percentile(y_std, percentile_bins)
observed_frequency, bins = (np.histogram(y_std, bins=percentile_cutoffs))
cum_observed_frequency = np.cumsum(observed_frequency)
# Loop through candidate distributions
for distribution in dist_names:
# Set up distribution and get fitted distribution parameters
dist = getattr(scipy.stats, distribution)
param = dist.fit(y_std)
print("\n\n".format(dist, param))
# Get expected counts in percentile bins
# cdf of fitted sistrinution across bins
cdf_fitted = dist.cdf(percentile_cutoffs, *param)
expected_frequency = []
for bin in range(len(percentile_bins)-1):
expected_cdf_area = cdf_fitted[bin+1] - cdf_fitted[bin]
expected_frequency.append(expected_cdf_area)
# Chi-square Statistics
expected_frequency = np.array(expected_frequency) * size
cum_expected_frequency = np.cumsum(expected_frequency)
ss = sum (((cum_expected_frequency - cum_observed_frequency) ** 2) / cum_observed_frequency)
chi_square_statistics.append(ss)
#Sort by minimum ch-square statistics
results = pd.DataFrame()
results['Distribution'] = dist_names
results['chi_square'] = chi_square_statistics
results.sort_values(['chi_square'], inplace=True)
print ('\nDistributions listed by goodness of fit:')
print ('............................................')
print (results)
【讨论】:
【参考方案5】:关于类似的问题 (see here),您可能会对 @Michel_Baudin 的回答解释感兴趣。他的代码评估了大约 40 个不同的可用 OpenTURNS 库,并根据 BIC 标准选择了最好的一个。看起来像这样:
import openturns as ot
sample = ot.Sample([[x] for x in your_data_list])
tested_factories = ot.DistributionFactory.GetContinuousUniVariateFactories()
best_model, best_bic = ot.FittingTest.BestModelBIC(sample, tested_factories)
【讨论】:
以上是关于如何找到真实数据的概率分布和参数? (Python 3)的主要内容,如果未能解决你的问题,请参考以下文章