在自定义交叉过滤器减少功能中避免多重总和

这个问题来自创建crossfilter数据集时遇到的一些困难,特别是如何对不同维度进行分组并计算派生值。 最终目标是使用维度和组来创建多个dc.js图。

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

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

如何创建自定义addremoveinit ,函数传入.reduce以便前两个不会多次相同的功能?

数据

假设我想监视多台机器的故障率(只是一个例子)。 我使用不同的维度来做到这一点:月份,机器的位置和故障类型。

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

| 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 |  .   |  .          |   .       |  .           |

预期

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

  • 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} $。
  • 理念

    从本质上讲,这种情况下重要的是夫妻(day, room) 。 即给一天和一个房间应该有一个附加费率(然后交叉过滤器应采取行动,以考虑其他过滤器)。

    因此,很长的路要走可以存储已经被使用,并且不求和夫妇machineCount他们-但我们还是要更新的failCount的值。

    尝试(失败)

    我的尝试是创建自定义缩减功能,并且不会将已经考虑在内的MachineCount相加。

    但是有一些意想不到的行为。 我相信这不是要走的路 - 所以我希望对此有一些建议。 //维度是以下之一:// ndx = crossfilter(data); // 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在三个不同的条形图中传递dimension, group

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

    有关实现,请参阅jsfiddle(https://jsfiddle.net/raino01r/0vjtqsjL/)。 不同的数字,但数据结构是相同的。 请注意,您希望Machine count为18(两个月),但总是会得到双倍(因为有两个不同的位置)。


    编辑

    减少+ dc.js

    在Ethan Jewett回答之后,我使用reductio来处理分组。 更新的小提琴在这里https://jsfiddle.net/raino01r/dpa3vv69/

    加总machineCount值时(month, room)我的reducer对象需要两个例外(month, room) 。 因此它的构建如下:

    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; })
    

    这似乎修复了图形渲染时的数字。

    但是 ,当过滤一个月并查看type图中的数字时,我确实有一种奇怪的行为。

    可能的方案

    相反,双创建两个异常,我可以在处理数据时合并两个字段。 也就是说,数据一经确定,我就会发现:

    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; })
    

    这个解决方案似乎工作。 然而,我不确定这是否是一个明智的做法:如果数据集很大,添加新功能可能会使事情变得非常缓慢!


    一些东西:

  • 不要在您的Crossfilter减速器中计算费率。 计算费率的组成部分。 这将保持既简单又快速。 在你的价值存取器中做实际的分工。

  • 你基本上有正确的想法。 我认为我立即看到了两个问题:

  • 在您的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; var count_to_sum = index ? v.machineCount:0; 代替。

  • 如果你想整理一个实际的例子,我敢肯定,我或其他人会很乐意为你效劳。

    你可能也想试试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)
    
    链接地址: http://www.djcxy.com/p/5603.html

    上一篇: Avoid multiple sums in custom crossfilter reduce functions

    下一篇: how to do a complex crossfilter reduction