dc.js 和 crossfilter 二级聚合到每小时平均计数
dc.js and crossfilter second level aggregation to average count per hour
我正在尝试稍微扩展这个问题中描述的问题:
dc.js and crossfilter reduce average counts per day of week
我想绘制一天中每小时的平均计数图表。我遵循了上面的解决方案,在自定义 reduce 中按天计算值,唯一的变化是按一天中的小时计算维度。这似乎运作良好,可以在以下 fiddle:
中看到
http://jsfiddle.net/dolomite/6eeahs6z/73/
顶部的条形图显示每小时的平均计数,下方的条形图显示每小时的总计数。所以第 22 小时的总计数为 47,平均计数为 4.2727...数据中有 11 天,所以这是正确的。
但是,当我单击工作日行图并过滤星期日时,我得到第 22 小时的总计数,共 4 小时,平均值为 0.3636...计算平均值时的分母仍包括所有工作日数据,与我过滤的工作日无关。因此,虽然总计数已过滤为周日仅显示 4,但它被除以数据中的总天数,而要求只是除以过滤器中选择的 day/s 的数量.
我知道解决方案在于修改自定义 reduce,但我被卡住了!任何关于我哪里出错的指示都将不胜感激。
hourAvgGroup = hourDim.group().reduce(
function (p, v) { // add
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) + 1 : 1);
p.avg = average_map(p.map);
return p;
},
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
p.avg = average_map(p.map);
return p;
},
function () { // init
return { map: d3.map(), avg: 0 };
}
)
function average_map(m) {
var sum = 0;
m.forEach(function(k, v) {
sum += v;
});
return m.size() ? sum / m.size() : 0;
}
m.size()
计算映射中的键数。问题是,即使一天分配了 0 条记录,密钥仍然存在,因此 m.size()
将其计入分母。解决方案是在计数为 0 时删除密钥。可能有更有效的方法来执行此操作,但最简单的解决方案是在自定义 reducer 中的删除函数中添加一行,以便该函数如下所示:
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
// If the day has 0 records, remove the key
if(p.map.has(day) && p.map.get(day) == 0) p.map.remove(day);
p.avg = average_map(p.map);
return p;
},
顺便说一句,我也建议不要在您的组中包括实际平均值和平均值计算。改为在 dc.js 图表 valueAccessor
中计算。对于每条添加或删除的记录,reducer 是 运行 一次。 valueAccessor
每个过滤器操作仅 运行 一次。
我正在尝试稍微扩展这个问题中描述的问题:
dc.js and crossfilter reduce average counts per day of week
我想绘制一天中每小时的平均计数图表。我遵循了上面的解决方案,在自定义 reduce 中按天计算值,唯一的变化是按一天中的小时计算维度。这似乎运作良好,可以在以下 fiddle:
中看到http://jsfiddle.net/dolomite/6eeahs6z/73/
顶部的条形图显示每小时的平均计数,下方的条形图显示每小时的总计数。所以第 22 小时的总计数为 47,平均计数为 4.2727...数据中有 11 天,所以这是正确的。
但是,当我单击工作日行图并过滤星期日时,我得到第 22 小时的总计数,共 4 小时,平均值为 0.3636...计算平均值时的分母仍包括所有工作日数据,与我过滤的工作日无关。因此,虽然总计数已过滤为周日仅显示 4,但它被除以数据中的总天数,而要求只是除以过滤器中选择的 day/s 的数量.
我知道解决方案在于修改自定义 reduce,但我被卡住了!任何关于我哪里出错的指示都将不胜感激。
hourAvgGroup = hourDim.group().reduce(
function (p, v) { // add
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) + 1 : 1);
p.avg = average_map(p.map);
return p;
},
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
p.avg = average_map(p.map);
return p;
},
function () { // init
return { map: d3.map(), avg: 0 };
}
)
function average_map(m) {
var sum = 0;
m.forEach(function(k, v) {
sum += v;
});
return m.size() ? sum / m.size() : 0;
}
m.size()
计算映射中的键数。问题是,即使一天分配了 0 条记录,密钥仍然存在,因此 m.size()
将其计入分母。解决方案是在计数为 0 时删除密钥。可能有更有效的方法来执行此操作,但最简单的解决方案是在自定义 reducer 中的删除函数中添加一行,以便该函数如下所示:
function (p, v) { // remove
var day = d3.time.day(v.EventDate).getTime();
p.map.set(day, p.map.has(day) ? p.map.get(day) - 1 : 0);
// If the day has 0 records, remove the key
if(p.map.has(day) && p.map.get(day) == 0) p.map.remove(day);
p.avg = average_map(p.map);
return p;
},
顺便说一句,我也建议不要在您的组中包括实际平均值和平均值计算。改为在 dc.js 图表 valueAccessor
中计算。对于每条添加或删除的记录,reducer 是 运行 一次。 valueAccessor
每个过滤器操作仅 运行 一次。