【问题标题】:Distribution plot is showing flat pdf分布图显示平面 pdf
【发布时间】:2020-05-29 23:49:39
【问题描述】:

在找到最佳参数后,我试图绘制我的数据的Probability Density Function (PDF) plot,但绘图显示的是一条平线而不是曲线。

  • 是缩放问题吗?
  • Continuous or Discrete data的问题吗?数据文件可用here
  • 这里的目的是得到最好的分布拟合,然后绘制 PDF 函数。
  • 我的数据值非常小,例如:0.21, 1.117 .etc。数据统计和PDF图如下所示:

我的脚本如下:

from time import time
from datetime import datetime
start_time = datetime.now()
import pandas as pd
pd.options.display.float_format = '{:.4f}'.format
import numpy as np
import pickle
import scipy
import scipy.stats
import matplotlib.pyplot as plt

data= pd.read_csv("line_RXC_data.csv",usecols=['R'],parse_dates=True, squeeze=True)
df=data

y_std=df
# del yy

import warnings
warnings.filterwarnings("ignore")


# Create an index array (x) for data

y=df
#
# Create an index array (x) for data

x = np.arange(len(y))
size = len(y)

#simple visualisation of the data
plt.hist(y)
plt.title("Histogram of resistance ")
plt.xlabel("Resistance data visualization ")
plt.ylabel("Frequency")
plt.show()

y_df = pd.DataFrame(y)
tt=y_df.describe()
print(tt)

dist_names = [
                'foldcauchy',
                'beta',
                'expon',
                  'exponnorm',
                'norm', 
                'lognorm',
                  'dweibull',
                'pareto',
                  'gamma'
]


x = np.arange(len(df))
size = len(df)
y_std = df
y=df
chi_square = []
p_values = []

# Set up 50 bins for chi-square test
# Observed data will be approximately evenly distrubuted aross all bins
percentile_bins = np.linspace(0,100,51)
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:
    s1 = time()
    # Set up distribution and get fitted distribution parameters
    dist = getattr(scipy.stats, distribution)
    # print("1")
    param = dist.fit(y_std)
    # print("2")
    # Obtain the KS test P statistic, round it to 5 decimal places
    p = scipy.stats.kstest(y_std, distribution, args=param)[1]
    p = np.around(p, 5)
    p_values.append(p)    
    # print("3")
    # Get expected counts in percentile bins
    # This is based on a 'cumulative distrubution function' (cdf)
    cdf_fitted = dist.cdf(percentile_cutoffs, *param[:-2], loc=param[-2], 
                          scale=param[-1])
    # print("4")
    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)

    # calculate chi-squared
    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.append(ss)
    print(f"chi_square {distribution} time: {time() - s1}")

#    print("std of predicted probability : ", np.std(cum_observed_frequency))   

# Collate results and sort by goodness of fit (best at top)

results = pd.DataFrame()
results['Distribution'] = dist_names
results['chi_square'] = chi_square
results['p_value'] = p_values
results.sort_values(['chi_square'], inplace=True)

# Report results

print ('\nDistributions sorted by goodness of fit:')
print ('----------------------------------------')
print (results)


#%%

# Divide the observed data into 100 bins for plotting (this can be changed)
number_of_bins = 100
bin_cutoffs = np.linspace(np.percentile(y,0), np.percentile(y,99),number_of_bins)

# Create the plot
plt.figure(figsize=(7, 4))
h = plt.hist(y, bins = bin_cutoffs, color='0.70')

# Get the top three distributions from the previous phase
number_distributions_to_plot = 5
dist_names = results['Distribution'].iloc[0:number_distributions_to_plot]


#%%
# Create an empty list to stroe fitted distribution parameters
parameters = []

# Loop through the distributions ot get line fit and paraemters

for dist_name in dist_names:
    # Set up distribution and store distribution paraemters
    dist = getattr(scipy.stats, dist_name)
    param = dist.fit(y)
    parameters.append(param)

    # Get line for each distribution (and scale to match observed data)
    pdf_fitted = dist.pdf(x, *param[:-2], loc=param[-2], scale=param[-1])
    scale_pdf = np.trapz (h[0], h[1][:-1]) / np.trapz (pdf_fitted, x)
    pdf_fitted *= scale_pdf

    # Add the line to the plot
    plt.plot(pdf_fitted, label=dist_name)

    # Set the plot x axis to contain 99% of the data
    # This can be removed, but sometimes outlier data makes the plot less clear
    plt.xlim(0,np.percentile(y,99))


# Add legend and display plotfig = plt.figure(figsize=(8,5)) 

plt.legend()
plt.title(u'Data distribution charateristics) \n' )
plt.xlabel(u'Resistance')
plt.ylabel('Frequency )')
plt.show()

# Store distribution paraemters in a dataframe (this could also be saved)
dist_parameters = pd.DataFrame()
dist_parameters['Distribution'] = (
        results['Distribution'].iloc[0:number_distributions_to_plot])
dist_parameters['Distribution parameters'] = parameters

# Print parameter results
print ('\nDistribution parameters:')
print ('------------------------')

for index, row in dist_parameters.iterrows():
    print ('\nDistribution:', row[0])
    print ('Parameters:', row[1] )

【问题讨论】:

  • 看起来确实像缩放问题。尝试摆脱那些灰色条,看看它是否有效。之后,您可以尝试添加第二个 y 轴,如下所示:matplotlib.org/gallery/api/two_scales.html
  • 尝试使用plt.hist(..., density=True) 来缩小直方图。现在直方图的 y 轴是 bin 计数。并且 pdf 的 y 轴被归一化。
  • 你的意思是在这一行:h = plt.hist(y, bins = bin_cutoffs, color='0.70')
  • 是的。 density=True 缩小直方图,使其更类似于 pdf。
  • 我听从了你的建议,但没有奏效。

标签: python matplotlib statistics distribution data-fitting


【解决方案1】:

如果您查看以下分类频率分析,您会发现只有 15 个不同的值分布在整个范围内,并且它们之间的差距很大,而不是一个连续的值。一半的观测值的值为 0.211,另外约 36% 的值出现在 1.117 处,约 8% 的值为 0.194,约 4% 的值为 0.001。我认为将其视为连续数据是错误的。

【讨论】:

  • @pjs..这是一个很好的数据演示。那么,总的来说,我们可以说这是离散数据吗? .其次,`概率密度函数(PDF)`适合离散数据还是连续数据?我们也可以在 python 中进行相同的频率分析吗?
  • 我不知道数据也不知道它的来源,但是当一个连续的范围将它的所有数据打包成 15 个特定值时,我称之为离散的。不,PDF 不适合离散数据——应该使用概率质量函数,它描述了与每个结果相关的概率。这就是上表的内容。 PMF 和 CDF 评估为概率,PDF 不评估。作为反例,考虑范围 (0,1) 上的三角形分布,模式为 0。PDF 计算结果为 f(0) = 2,证明它不是概率(因为公理上所有概率都
  • 我敢打赌,有一个库可以做类似于我上面所做的分析的事情,但我是一个统计学家,不喜欢 Python,所以我不能告诉你它是什么是。但是,构建一个维护值计数器的字典并不难,也不难将所有这些计数相加并将每个值的计数表示为总数的比例。
  • 如果您正在寻找合适的方法来绘制分类数据,搜索一下就会出现 catplot、barplot 和 countplot here
猜你喜欢
  • 1970-01-01
  • 2017-09-10
  • 1970-01-01
  • 2021-12-05
  • 2021-05-02
  • 1970-01-01
  • 1970-01-01
  • 2020-06-21
  • 2011-01-19
相关资源
最近更新 更多