如何更好地适应seaborn的小提琴图

17
以下代码给我提供了一个非常漂亮的小提琴图(以及内部的箱线图)。
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

foo = np.random.rand(100)
sns.violinplot(foo)
plt.boxplot(foo)
plt.show()

output

到目前为止还不错。然而,当我查看变量foo时,它不包含任何负值。这里的seaborn图表似乎有误导性。普通的matplotlib箱线图会给出更接近我预期的结果。
我该如何制作一个更适合的小提琴图(不显示错误的负值)?

嗯,这可能不是那么容易。这是 KDE 的一个特殊情况,它不知道在 0 处有一个硬边界。如果您对此问题感兴趣,请参见:http://stats.stackexchange.com/questions/65866/good-methods-for-density-plots-of-non-negative-variables-in-r?lq=1 - cel
@cel 谢谢。这正是我所想的。但它不能更紧吗? - n1000
1
有相应的算法可以实现。在这个回答中可以看到令人印象深刻的结果:http://stats.stackexchange.com/a/71291。然而,我还没有在Python中看到它的实现。 - cel
1个回答

25

正如评论中所指出的,这是高斯核密度估计潜在假设带来的结果(我不确定是否应该称其为“人工制品”)。正如已经提到的那样,这在某种程度上是不可避免的,如果您的数据不符合这些假设,您最好只使用箱线图,它只显示实际数据中存在的点。

然而,在您的回复中,您问到是否可以使拟合“更紧密”,这可能有几种含义。

其中一种答案可能是改变平滑核的带宽。您可以使用bw参数来实现这一点,它实际上是一个比例因子;将使用的带宽为bw * data.std()

data = np.random.rand(100)
sns.violinplot(y=data, bw=.1)

在此输入图片描述

另一个答案可能是在数据点的极端值处截断小提琴图。核密度估计仍将用延伸到数据边界之外的密度进行适配,但不会显示其尾部。您可以使用“cut”参数来指定带宽超出极端值的单位数。要截断,请将其设置为0:

sns.violinplot(y=data, cut=0)

在此输入图片描述

顺便提一下,violinplot 的 API 在 0.6 版本中 将会有所改变,而我现在使用的是开发版本,但是当前发布版本中 bwcut 参数也存在,并且行为上更或多或少相同。


1
我不喜欢使用“cut”解决方案。它隐藏了“KDE”无法正确适应这样的密度函数的事实。接近边界0的密度是具有误导性的,因为即使相应的直方图在0处具有最大值,您仍将获得这样的密度估计。 - cel
请查看 https://github.com/mwaskom/seaborn/issues/525 上的功能请求(等待 statsmodels 上游更改)。 - naught101
+1 伟大的解决方案。这是一个快速而干净的解决方案。显然,极端的切割将表明kde和底层密度之间存在一些极端差异。 - MachineLearner
我喜欢“Cut”解决方案,它可以让你了解你的分布与边界有多接近。 - Jeff Ellen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接