1 python statistics kernel-density
我遇到过一些可以进行核密度估计的方法,这些方法将为数据样本提供 PDF:
使用上述任何一种方法我都可以生成 PDF,但是我想知道如何获取我正在生成的 PDF 的 CDF。在数学中,我知道您可以对 PDF 进行积分以获得 CDF,但问题是这些方法仅提供 x 和 y 点,而不是要积分的函数。
我想知道如何将给出的数据转换为 CDF 图,或者找到数据的 PDF 函数,然后积分以获得 CDF。或者使用另一种方法,其中输出是 CDF 而不是 PDF。
让我们创建一些虚拟数据来进行讨论:
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
np.random.seed(123)
data = stats.norm(loc=0, scale=1).rvs(10**4)
Run Code Online (Sandbox Code Playgroud)
这是该包的基本想法scipy.stats
。
我们可以使用专用工具来估计 KDE,例如gaussian_kde
:
kde = stats.gaussian_kde(data)
Run Code Online (Sandbox Code Playgroud)
它公开了一个PDF
要每次评估的函数x
,但缺少CDF
.
使用Kolmogorov-Smirnov检验检查样本,我们不能拒绝阈值为 10% 的原假设(两个分布相同):
stats.ks_2samp(data, kde.resample(100).squeeze())
# KstestResult(statistic=0.0969, pvalue=0.29163373800871994)
Run Code Online (Sandbox Code Playgroud)
该scipy.stats
包还公开了一个可供rv_continous
继承的通用类。如文档中所述:
rv_continuous
新的随机变量可以通过对类进行子类化并至少重新定义_pdf
或_cdf
方法(标准化为位置 0 和尺度 1)来定义。
所以我们可以使用这个有目的的逻辑来填补空白。如果不考虑任何性能,它可以归结为:
class KDEDist(stats.rv_continuous):
def __init__(self, kde, *args, **kwargs):
super().__init__(*args, **kwargs)
self._kde = kde
def _pdf(self, x):
return self._kde.pdf(x)
Run Code Online (Sandbox Code Playgroud)
然后我们使用实验性 KDE 创建底层对象。
X = KDEDist(kde)
stats.ks_2samp(data, X.rvs(size=100)) # This call is kind of intensive
# KstestResult(statistic=0.0625, pvalue=0.8113077271721811)
Run Code Online (Sandbox Code Playgroud)
现在我们可以自然地 - 至少在 API 调用方面 -也可以评估PDF
和:CDF
fig, axe = plt.subplots()
axe.hist(data, density=1)
axe.plot(x, X.pdf(x))
axe.plot(x, X.cdf(x))
Run Code Online (Sandbox Code Playgroud)
它返回:
请注意,这种方法可以回答您的问题,但并不具有性能。KDE 计算成本高昂,主要是因为内核跨越整个数据空间(高斯在无穷大达到零)。因此,没有截止的特征计算是基于每次评估时数据集的所有观察结果。
更改窗口函数可以极大地提高性能。例如:三角窗口将在整个数据集上具有固定的跨度,并减少数据集范围和大小的计算。
阅读文档,似乎rv_continuous
最初是为了实现具有分析定义的新连续变量而设计的。
无论如何,如果未实现(覆盖)底层方法,该类会为其他统计数据提供自动解析/集成。
选择此方法时,如果您希望使其性能更高、更稳健(数值稳定性),则需要实现缺失的逻辑。
如果您可以放宽KDE
需求并满足直方图分布,那么您可以依赖它rv_histogram
,它基本上基于分箱分布执行相同的操作:
hist = np.histogram(data, bins=100)
hist_dist = stats.rv_histogram(hist)
stats.ks_2samp(data, hist_dist.rvs(size=100))
# KstestResult(statistic=0.0577, pvalue=0.8778871545532821)
Run Code Online (Sandbox Code Playgroud)
返回:
如果理论上可以接受,我们可以通过从 KDE 创建预期直方图来混合这两种策略:
hist = np.histogram(data, bins=1000)
hist_kde = kde.pdf(hist[1][:-1] + np.diff(hist[1]))
hist_dist_kde = stats.rv_histogram([hist_kde, hist[1]])
stats.ks_2samp(data, hist_dist_kde.rvs(size=100))
# KstestResult(statistic=0.1067, pvalue=0.19541766226890545)
Run Code Online (Sandbox Code Playgroud)
然后,CDF 相对于 KDE 具有相对平滑度(它仍然是直方图),并且连续变量对象具有尽可能高的性能rv_histogram
。