避免在自定义交叉过滤器归约函数中进行多次求和

2024-03-23

这个问题是由于创建过程中遇到的一些困难而产生的crossfilter数据集,特别是如何对不同维度进行分组并计算派生值。最终目标是拥有一批dc.js使用维度和组的图表。

(小提琴示例https://jsfiddle.net/raino01r/0vjtqsjL/ https://jsfiddle.net/raino01r/0vjtqsjL/)

Question

在继续解释设置之前,关键问题如下:

如何创建自定义add, remove, init, 传入的函数.reduce这样前两个就不会多次对同一特征求和?

Data

假设我想监控多台机器的故障率(仅作为示例)。我使用不同的维度来做到这一点:月份、机器位置和故障类型。

例如我有以下形式的数据:

| month   | room | failureType | failCount | machineCount |
|---------|------|-------------|-----------|--------------|
| 2015-01 |  1   |  A          |  10       |  5           |
| 2015-01 |  1   |  B          |   2       |  5           |
| 2015-01 |  2   |  A          |   0       |  3           |
| 2015-01 |  2   |  B          |   1       |  3           |
| 2015-02 |  .   |  .          |   .       |  .           |

Expected

对于给定的三个维度, 我应该:

  • Month_1_rate = $\frac{10+2+0+1}{5+3}$;
  • room_1_rate = $\frac{10+2}{5}$;
  • type_A_rate = $\frac{10+0}{5+3}$。

Idea

本质上,在这个环境中最重要的是夫妻俩(day, room)。 IE。给定一天和一个房间,应该有一个附加费率(然后交叉过滤器应该考虑其他过滤器)。

因此,一种方法可能是存储已经使用过的对,并且不求和machineCount对于他们 - 然而我们仍然想更新failCount value.

尝试(失败)

我的尝试是创建自定义归约函数而不是求和MachineCount这些已经被考虑在内。

然而,有一些意想不到的行为。我确信这不是正确的方法 - 所以我希望对此有一些建议。// 维度是以下之一: // ndx = crossfilter(数据); // ndx.dimension(function(d){return d.month;}) // ndx.dimension(function(d){return d.room;}) // ndx.dimension(function(d){return d.failureType;}) // 目标:有一个通用的方法来获取给定维度的组:

function get_group(dim){
    return dim.group().reduce(add_rate, remove_rate, initial_rate);
}

// month is given as datetime object
var monthNameFormat = d3.time.format("%Y-%m");
//
function check_done(p, v){
    return p.done.indexOf(v.room+'_'+monthNameFormat(v.month))==-1;
}    

// The three functions needed for the custom `.reduce` block.
function add_rate(p, v){
    var index = check_done(p, v);
    if (index) p.done.push(v.room+'_'+monthNameFormat(v.month));
    var count_to_sum = (index)? v.machineCount:0;
    p.mach_count += count_to_sum;
    p.fail_count += v.failCount;
    p.rate = (p.mach_count==0) ? 0 : p.fail_count*1000/p.mach_count;
    return p;
}
function remove_rate(p, v){
    var index = check_done(p, v);
    var count_to_subtract = (index)? v.machineCount:0;
    if (index) p.done.push(v.room+'_'+monthNameFormat(v.month));
    p.mach_count -= count_to_subtract;
    p.fail_count -= v.failCount;
    p.rate = (p.mach_count==0) ? 0 : p.fail_count*1000/p.mach_count;
    return p;
}
function initial_rate(){
    return {rate: 0, mach_count:0, fail_count:0, done: new Array()};
}

与 dc.js 连接

如前所述,需要前面的代码来创建dimension, group使用三个不同的条形图传递dc.js.

每个图都会有.valueAccessor(function(d){return d.value.rate};).

请参阅 jsfiddle (https://jsfiddle.net/raino01r/0vjtqsjL/ https://jsfiddle.net/raino01r/0vjtqsjL/),用于实施。数字不同,但数据结构相同。请注意您期望的小提琴中的Machine count18 岁(两个月),但是你总是得到双份(因为两个不同的地点)。


Edit

减少+dc.js

根据 Ethan Jewett 的回答,我使用了reductio照顾分组。更新的小提琴在这里https://jsfiddle.net/raino01r/dpa3vv69/ https://jsfiddle.net/raino01r/dpa3vv69/

My reducer对象需要两个异常(month, room),当求和时machineCount价值观。因此它的构建如下:

var reducer = reductio()
reducer.value('mach_count')
       .exception(function(d) { return d.room; })
       .exception(function(d) { return d.month; })
       .exceptionSum(function(d) { return d.machineCount; })
reducer.value('fail_count')
       .sum(function(d) { return d.failCount; })

这似乎可以修复渲染图表时的数字。

However,在过滤一个月并查看中的数字时,我确实有一种奇怪的行为type graph.

Possible solution

相反,双重创建两个异常,我可以在处理数据时合并两个字段。 IE。一旦定义了数据,我就可以:

data.foreach(function(x){
    x['room_month'] = x['room'] + '_' + x['month'];
})

那么上面的归约代码应该变成:

var reducer = reductio()
reducer.value('mach_count')
       .exception(function(d) { return d.room_month; })
       .exceptionSum(function(d) { return d.machineCount; })
reducer.value('fail_count')
       .sum(function(d) { return d.failCount; })

这个解决方案似乎有效。但是我不确定这是否是明智的做法:如果数据集很大,添加新功能可能会大大减慢速度!


一些东西:

  1. 不要在 Crossfilter 减速器中计算费率。计算比率的组成部分。这将变得更简单、更快。在您的值访问器中进行实际的除法。

  2. 你的想法基本上是正确的。我认为我立即看到两个问题:

    • In your remove_rate您没有将钥匙从p.done大批。你应该做类似的事情if (index) p.done.splice(p.done.indexOf(v.room+'_'+monthNameFormat(v.month)), 1);将其删除。

    • 在你的reduce函数中,index是一个布尔值。(index == -1)永远不会评价为true,IIRC。所以你添加的机器数量将永远是0。使用var count_to_sum = index ? v.machineCount:0;反而。

如果您想编写一个可行的示例,我相信我或其他人会很乐意为您提供它。

您可能还想尝试Reductio https://github.com/crossfilter/reductio。 Crossfilter 减速器很难正确且高效地完成,因此使用库来提供帮助可能是有意义的。使用 Reductio,创建一个计算机器计数和故障计数的组,如下所示:

var reducer = reductio()
reducer.value('mach_count')
  .exception(function(d) { return d.room; })
  .exceptionSum(function(d) { return d.machineCount; })
reducer.value('fail_count')
  .sum(function(d) { return d.failCount; })

var dim = ndx.dimension(...)
var grp = dim.group()
reducer(group)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

避免在自定义交叉过滤器归约函数中进行多次求和 的相关文章

随机推荐