Seaborn KDEPlot-数据变化是否不够?

我有一个包含约900行的数据框;我正在尝试为某些列绘制KDEplots。在某些列中,大多数值是相同的最小值。当我包含太多最小值时,KDEPlot突然停止显示最小值。例如,以下内容包含600个值,其中最小值为450,并且该图看起来不错:

og:title

Seaborn KDEPlot-数据变化是否不够?

但是包含451个最小值会产生非常不同的输出:

<NavigationPrompt when={this.state.simulationView}>
          {({ onconfirm,onCancel }) => (
            <Dialog
              when
              onClose={() => { this.setState({ toggleConfirmationDialogue: false }); }}
              aria-labelledby="customized-dialog-title"
              open={this.state.simulationView}
            >
              <ExitSimulationDialog
                title={'Exit Simulation'}
                onClickConfirm={() => { onconfirm(); this.setState({ simulationView: false }); }}
                dialogClose={onCancel}
              />
            </Dialog>
  )}
        </NavigationPrompt>

Seaborn KDEPlot-数据变化是否不够?

最终,我想相互绘制不同列的双变量KDEPlot,但是我想首先理解这一点。

aaassdqw 回答:Seaborn KDEPlot-数据变化是否不够?

问题是为kde的“带宽”选择了默认算法。 The default method'scott',当有许多相等的值时,它并不是很有用。

带宽是位于每个采样点并求和的高斯宽度。较低的带宽更接近数据,较高的带宽使一切平滑。最佳地点在中间。在这种情况下,bw=0.3是一个不错的选择。为了比较不同的kde,建议每次选择完全相同的带宽。

下面是一些示例代码,用于显示bw='scott'bw=0.3之间的区别。示例数据是标准正态分布中的150个值以及400、450或500个固定值。

import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns; sns.set()

fig,axs = plt.subplots(nrows=2,ncols=3,figsize=(10,5),gridspec_kw={'hspace':0.3})

for i,bw in enumerate(['scott',0.3]):
    for j,num_same in enumerate([400,450,500]):
        y = np.concatenate([np.random.normal(0,1,150),np.repeat(-3,num_same)])
        sns.kdeplot(y,bw=bw,ax=axs[i,j])
        axs[i,j].set_title(f'bw:{bw}; fixed values:{num_same}')
plt.show()

第三幅图警告说,无法使用Scott的建议带宽来绘制kde。

example plot

PS:如@mwascom在评论中所述,在这种情况下,使用scipy.statsmodels.nonparametric.kde(而不是scipy.stats.gaussian_kde)。那里的默认值为 "scott" - 1.059 * A * nobs ** (-1/5.),where A is min(std(X),IQR/1.34) min()阐明了行为上的突然变化。 IQR"interquartile range"第75个百分点与第25个百分点之间的差异

,

如果样本具有重复值,则表示基础分布不连续。在为说明问题而显示的数据中,我们可以在左侧看到Dirac分布。内核平滑可能会应用于此类数据,但要格外小心。确实,为了近似此类数据,我们可以使用内核平滑,其中与Dirac相关的带宽为零。但是,在大多数KDE方法中,所有内核原子只有一个带宽。此外,用于计算带宽的各种规则是基于对分布的PDF的二阶导数的近似性的某种估计。这不能应用于不连续的分布。

但是,我们可以尝试将样本分为两个子样本:

  • 具有复制的子样本,
  • 具有独特实现的子样本。

(Johanc已经提到了这个想法)。

以下是尝试执行此分类的尝试。 np.unique方法用于计算复制实现的出现次数。复制值与狄拉克斯相关,混合物中的重量由样品中这些复制值的分数估算。剩下的实现,唯一性,然后用于估计KDE的连续分布。

以下功能将有助于克服draw带有OpenTURNS的Mixtures方法的当前实现方式的局限性。

def DrawMixtureWithDiracs(distribution):
    """Draw a distributions which has Diracs.
    https://github.com/openturns/openturns/issues/1489"""
    graph = distribution.drawPDF()
    graph.setLegends(["Mixture"])
    for atom in distribution.getDistributionCollection():
        if atom.getName() == "Dirac":
            curve = atom.drawPDF()
            curve.setLegends(["Dirac"])
            graph.add(curve)
    return graph

以下脚本使用包含Dirac和高斯分布的Mixture创建一个用例。

import openturns as ot
import numpy as np
distribution = ot.Mixture([ot.Dirac(-3.0),ot.Normal()],[0.5,0.5])
DrawMixtureWithDiracs(distribution)

这是结果。

The PDF of a Mixture with a Dirac

然后我们创建一个示例。

sample = distribution.getSample(100)

这是您的问题开始的地方。我们计算每个实现的发生次数。

array = np.array(sample)
unique,index,count = np.unique(array,axis=0,return_index=True,return_counts=True)

对于所有实现,复制值都与Diracs相关联,唯一值放在单独的列表中。

sampleSize = sample.getSize()
listOfDiracs = []
listOfWeights = []
uniqueValues = []
for i in range(len(unique)):
    if count[i] == 1:
        uniqueValues.append(unique[i][0])
    else:
        atom = ot.Dirac(unique[i])
        listOfDiracs.append(atom)
        w = count[i] / sampleSize
        print("New Dirac =",unique[i]," with weight =",w)
        listOfWeights.append(w)

连续原子的重量是狄拉克斯的重量之和的互补。这样,权重的总和将等于1。

complementaryWeight = 1.0 - sum(listOfWeights)
weights = list(listOfWeights)
weights.append(complementaryWeight)

最简单的部分是:独特的实现可用于拟合内核平滑。然后将KDE添加到原子列表中。

sampleUniques = ot.Sample(uniqueValues,1)
factory = ot.KernelSmoothing()
kde = factory.build(sampleUniques)
atoms = list(listOfDiracs)
atoms.append(kde)

Etvoilà:混合物已准备就绪。

mixture_estimated = ot.Mixture(atoms,weights)

以下脚本比较了初始混合物和估计的混合物。

graph = DrawMixtureWithDiracs(distribution)
graph.setColors(["dodgerblue3","dodgerblue3"])
curve = DrawMixtureWithDiracs(mixture_estimated)
curve.setColors(["darkorange1","darkorange1"])
curve.setLegends(["Est. Mixture","Est. Dirac"])
graph.add(curve)
graph

该数字似乎令人满意,因为连续分布是根据子样本估计的,子样本的大小仅等于50,即整个样本的一半。

Approximation of a Mixture containing a Dirac with kernel smoothing

本文链接:https://www.f2er.com/2355951.html

大家都在问