如何确定将给定数据分箱成平滑直方图的网格?
How to determine a grid that bins the given data into a smooth histogram?
描述
我有一些模拟数据应该合并到直方图中(使用 sum
合并)。
原始数据如下图所示。蓝点是要分箱的数据,红线是定义分箱边界的 logscale
网格。
当使用正确的 bin 数 (50) 时,结果 binned 直方图是一条平滑的曲线。
但是,如果我使用了不正确的网格大小,例如 58,结果会出现振荡
要明白原因,请看下图不正确的网格:好像是网格把一些周期性数据分割错了周期,造成数据点的摆动赋值,数据震荡。
问题
目前,我通过反复试验找到最佳网格。我想知道是否有一种简单的方法可以找到将数据分箱成平滑曲线的网格(假设始终存在)?
示例数据
示例数据N
在此gist上传。第一列是Size
,第二列是Count
.
我创建了一个样本colab notebook来重现剧情。
谢谢!
这仍然是 'trial and error',但至少在程序上是这样。我假设我们只想找出垃圾箱的数量。
让我们检查一定数量的箱子以找出最好的箱子。我们将最好的定义为最小化 'counts' 日志的绝对差异平均值的那个,对正差异(代表图中的跳跃)施加巨大的惩罚。
def judge_grid(N, grid, pos_penalty=1e5):
stat, bin_edges, _ = binned_statistic(N[:, 0], N[:, 1], statistic="sum", bins=grid)
logcounts = np.log(stat) - np.log(bin_edges[1:] - bin_edges[:-1])
d = np.diff(logcounts)
# Huge penalty for positive difference.
ad = np.where(d > 0, d * pos_penalty, -d)
return np.mean(ad)
lo = np.log10(1e-5)
hi = np.log10(1.0)
min_bins = 10
max_bins = 80
best_num_bins = min(range(min_bins, 1+max_bins),
key=lambda b: judge_grid(N, np.logspace(lo, hi, b)))
print(best_num_bins)
对于你的例子这个 returns 50.
描述
我有一些模拟数据应该合并到直方图中(使用 sum
合并)。
原始数据如下图所示。蓝点是要分箱的数据,红线是定义分箱边界的 logscale
网格。
当使用正确的 bin 数 (50) 时,结果 binned 直方图是一条平滑的曲线。
但是,如果我使用了不正确的网格大小,例如 58,结果会出现振荡
要明白原因,请看下图不正确的网格:好像是网格把一些周期性数据分割错了周期,造成数据点的摆动赋值,数据震荡。
问题
目前,我通过反复试验找到最佳网格。我想知道是否有一种简单的方法可以找到将数据分箱成平滑曲线的网格(假设始终存在)?
示例数据
示例数据N
在此gist上传。第一列是Size
,第二列是Count
.
我创建了一个样本colab notebook来重现剧情。
谢谢!
这仍然是 'trial and error',但至少在程序上是这样。我假设我们只想找出垃圾箱的数量。
让我们检查一定数量的箱子以找出最好的箱子。我们将最好的定义为最小化 'counts' 日志的绝对差异平均值的那个,对正差异(代表图中的跳跃)施加巨大的惩罚。
def judge_grid(N, grid, pos_penalty=1e5):
stat, bin_edges, _ = binned_statistic(N[:, 0], N[:, 1], statistic="sum", bins=grid)
logcounts = np.log(stat) - np.log(bin_edges[1:] - bin_edges[:-1])
d = np.diff(logcounts)
# Huge penalty for positive difference.
ad = np.where(d > 0, d * pos_penalty, -d)
return np.mean(ad)
lo = np.log10(1e-5)
hi = np.log10(1.0)
min_bins = 10
max_bins = 80
best_num_bins = min(range(min_bins, 1+max_bins),
key=lambda b: judge_grid(N, np.logspace(lo, hi, b)))
print(best_num_bins)
对于你的例子这个 returns 50.