如何在crossfilter中对flat.reduce进行平面数据处理

时间:2014-03-05 19:34:43

标签: javascript mapreduce crossfilter dc.js

crossfilter新手。我有一个平面数据,如下所示:

 id,name,patientId,conditionId,isPrimary,age,gender,race,Status,CGI
 1,M1,1,c1,Y,33,Male,White,Discharged,0
 2,M2,1,c1,N,33,Male,White,Discharged,0
 3,M3,1,c2,N,33,Male,White,Discharged,0
 4,M4,1,c2,N,33,Male,White,Discharged,0
 5,M5,1,c3,N,33,Male,White,Discharged,0
 6,M6,1,c3,N,33,Male,White,Discharged,0
 25,M1,5,c1,Y,33,Male,White,Discharged,1
 26,M7,5,c2,N,33,Male,White,Discharged,1
 27,M4,5,c4,N,33,Male,White,Discharged,1
 28,M4,5,c1,N,33,Male,White,Discharged,1
 29,M4,5,c2,N,33,Male,White,Discharged,1
 30,M5,5,c4,N,33,Male,White,Discharged,1
 29,M2,6,c1,Y,33,Male,White,Discharged,1
 30,M2,7,c1,Y,33,Male,White,Discharged,1

我想对conditionId进行统计,但由于patientId标识属于同一个人的多个记录,因此值c1的计数应为4(属于patientId 1,5,6,7) - 因为同一患者可能有多个记录(例如,patientId为1,重复6次,其中两个有c1,应该只计数一次)。我很难在group.reduce上写conditionId,但甚至无法开始。

提前致谢。

2 个答案:

答案 0 :(得分:0)

这是一种做法。在示例中,我假设第一个值是patientId,第二个值是conditionId。代码会跟踪已经看到的patientIdconditionId的分组键并忽略它们。

var countMap = [
    [1, 'c1'],
    [1, 'c1'],
    [2, 'c1'],
    [2, 'c2']
].reduce(function (r, v) {
    var condition = v[1],
        groupKey = v[0] + condition;

    if (!r.seen[groupKey]) {
        r.seen[groupKey] = true; 
        r.count[condition] = (r.count[condition] || 0) + 1;
    }

    return r;

}, {seen: {}, count: {}}).count;


countMap.c1; //2
countMap.c2; //1

我不知道crossfilter或dc.js,这就是我给你一个vanilla JS解决方案的原因。

答案 1 :(得分:0)

在Crossfilter中执行此操作有点复杂,但解决方案类似于@plalx提供的解决方案。

这是我在其中一个项目中使用的辅助函数。它并不完美,并且有点优化以减少字典查找,因此它不是最易读的。基本思想是你需要保留每组之前看到的值的字典。您只需要记住患者,因为已根据您所在的群体了解病情:

function reduceHelper(accessorFunction) {
        var internalCount;
        return {
            add: function (p, v) {
                if(p.unique.has(accessorFunction(v))) {
                    internalCount = p.unique.get(accessorFunction(v));
                    p.unique.set(accessorFunction(v), internalCount + 1);
                } else {
                    p.unique.set(accessorFunction(v), 1);
                    ++p.count;
                }
                return p;
            },
            remove: function (p, v) {
                if(p.unique.has(accessorFunction(v))) {
                    internalCount = p.unique.get(accessorFunction(v));
                    if(internalCount == 1) {
                        p.unique.remove(accessorFunction(v));
                        --p.count;
                    } else {
                        p.unique.set(accessorFunction(v), internalCount - 1);
                    }
                }
                return p;
            },
            init: function () {
                return {unique: d3.map(), count: 0};
            }
        };
    }

您需要在数据上创建一个Crossfilter(xfilter),然后:

var helperFunctions = reduceHelper(function(d) { return d.patientId; });
var dim = xfilter.dimension(function (d) { return d.conditionId; };
var group = dim.group()
              .reduce(helperFunctions.add, helperFunctions.remove, helperFunctions.init);

您的小组现在将计算每种病情的患者人数。如果某个患者的病情出现不止一次,该患者仍然只会被计算一次。至少,如果我的解决方案正常运行: - )