0

如何使用 python创建连续均匀分布的 pdf 和 cdf 的交互式图?

均匀分布

我想有交互式滑块,我可以用它来调整分布的参数。

这有助于更好地了解该分布在不同参数值下的行为。

4

2 回答 2

2

1. 最简单的方法是使用scipy.stats.uniform()获取分布的 pdf 和 cdf,然后使用pn.interact()获取参数的交互式滑块:

# import libraries
from scipy import stats
import pandas as pd
import hvplot.pandas
import panel as pn
pn.extension()
import panel.widgets as pnw
import holoviews as hv
hv.extension('bokeh')


# define pdf and cdf for cont uniform distr and return plots
def get_interactive_plot_cont_uniform(loc=1, scale=5):
    continuous_uniform = stats.uniform(loc=loc, scale=scale)
    
    x_values = np.linspace(0, 10, num=1000)
    fx_values = continuous_uniform.pdf(x_values)
    Fx_values = continuous_uniform.cdf(x_values)
    
    interactive_plot = (
        hv.Curve((x_values, fx_values), label='PDF') 
        + hv.Curve((x_values, Fx_values), label='CDF'))
    return interactive_plot

# use pn.interact() to get interactive sliders 
# and define the sliders yourself for more flexibility
pn.interact(
    get_interactive_plot_cont_uniform, 
    loc=pnw.FloatSlider(
       name='Value for loc', value=1., 
       start=0, step=0.5, end=10),
    scale=pnw.FloatSlider(
       name='Value for scale', value=5., 
       start=0, step=0.5, end=10),
)

生成的带有滑块的交互式绘图:

具有连续均匀分布滑块的交互式绘图

2. 更广泛、更灵活的示例,可以更直观地设置参数a和b:

# create sliders to adjust parameter a and b
param_a = pnw.FloatSlider(name='Value for parameter a', value=1., start=0, step=0.5, end=10)
param_b = pnw.FloatSlider(name='Value for parameter b', value=6., start=0, step=0.5, end=10)

# get interactivity by using following decorator
@pn.depends(param_a, param_b)
def get_interactive_cont_uniform(param_a, param_b):
    
    # define the uniform distribution
    # scale in scipy.stats.uniform is b - a
    loc = param_a
    scale = param_b - param_a
    continuous_uniform = stats.uniform(loc=loc, scale=scale)

    # calculate x and y values for pdf and cdf and put in dataframe
    x_values = np.linspace(0, 10, num=1000)
    fx_values = continuous_uniform.pdf(x_values)
    Fx_values = continuous_uniform.cdf(x_values)

    df = pd.DataFrame({
        'x': x_values, 
        'f(x)': fx_values,
        'F(x)': Fx_values,
    })

    # create pdf and cdf plot
    pdf_plot = df.hvplot.line(
        x='x', 
        y='f(x)', 
        ylim=(0, 1.02), 
        ylabel='f(x) - pdf values', xlabel='',
        title=f'pdf where a={param_a} and b={param_b}',
        height=225,
    ).opts(fontscale=1.25)
    
    cdf_plot = df.hvplot.line(
        x='x', 
        y='F(x)', 
        ylim=(0, 1.02), 
        ylabel='F(x) - cdf values',
        title=f'cdf where a={param_a} and b={param_b}',
        height=225,
    ).opts(fontscale=1.25)
    
    return (pdf_plot + cdf_plot).cols(1)

# use pyviz panel to get a nice view of sliders and the plots
pn.Column(
    pn.pane.Markdown("## Continuous Uniform Distribution"),
    pn.Row(param_a, param_b),
    pn.Row(get_interactive_cont_uniform)
)
于 2020-12-30T21:00:54.407 回答
1

要建立在另一个答案的基础上,您还可以使用panel实现的面向类的方法。这是我最喜欢的方法,因为它使您的代码保持美观和模块化。bokeh此外,它直接通过而不是通过holoviews(我个人通常在围栏上)直接绘制。使用bokeh而不是可以holoviews让您更好地控制您的情节,但出于这些目的,您选择哪条路线并不重要。

.show()此代码段在笔记本中工作,但可以通过更改对方法的调用.servable()并使用以下命令从命令行/终端运行脚本来适应脚本格式:panel serve file.py --show

from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
import panel as pn
import param
from scipy import stats

class UniformViewer(param.Parameterized):
    a = param.Number(1, bounds=(0, 15), step=.5)
    b = param.Number(4, bounds=(0, 15), step=.5, inclusive_bounds=(False, True))
    
    def __init__(self, **params):
        super().__init__(**params)
        
        # Initialize 2 plots with common arguments
        plot_kwargs = {
            "height": 250,
            "width": 250,
            "y_range": (-.1, 1.1)
        }
        self.p_pdf = figure(title="PDF", **plot_kwargs)
        self.p_cdf = figure(title="CDF", **plot_kwargs)
        
        # Calculate range of data based on parameter bounds
        a_min, a_max = self.param.a.bounds
        b_min, b_max = self.param.b.bounds
        
        # Create x-values for pdf/cdf calculations
        x_min, x_max = min(a_min, b_min), max(a_max, b_max)
        self.x = np.linspace(x_min, x_max, 1000)
        
        # store x values in our CDS since they won't change
        self.cds = ColumnDataSource({"x": self.x}) 
        self.update_cds() # Populate cdf/pdf values into the CDS before plotting
        
        # Draw our pdf and cdf on their respective figures
        self.p_pdf.line(x="x", y="pdf", source=self.cds)
        self.p_cdf.line(x="x", y="cdf", source=self.cds)
        
    # Add callback that executes anytime self.a or self.b changes
    @param.depends("a", "b", watch=True)
    def update_cds(self):
        # Calcualte the uniform distribution using
        # self.a as the left endpoint and self.b as the right endpoint
        uniform_dist = stats.uniform(loc=self.a, scale=self.b-self.a)
        
        self.cds.data.update({
            "pdf": uniform_dist.pdf(self.x),
            "cdf": uniform_dist.cdf(self.x)
        })
    
    def view(self):
        return pn.Row(self.p_pdf, self.p_cdf)
    
interactive_plot = UniformViewer()

pn.Column(interactive_plot, interactive_plot.view()).show()

在此处输入图像描述

于 2020-12-30T22:12:51.877 回答