如何进行复杂的交叉过滤减少
how to do a complex crossfilter reduction
我正在尝试使用自定义缩减(reduceAdd、reduceRemove 等)创建一个用于放入 dc.js 的变量,但我不知道如何对其进行编码。
我在这些 reduce 函数之外编写了函数,现在必须在 reduce 函数内部复制相同的函数,以便对绘制的图形使用相同的函数。为外部reduce函数编写的逻辑和代码如下
逻辑:对于每个唯一的 contact_week 可用(日期),找到 week_number 的最大值,然后求和 TOTCOUNT 变量和 DECAY_CNT 变量并计算百分比(DECAY_CNT/ TOTCOUNT) .
这里是没有使用crossfilter的原始代码:
//Decay % logic
var dates = d3.map(filter1,function(d) { return d.CONTACT_WEEK;}).keys() ;
console.log(dates);
var sum1,sum2 = 0;
for(var i=0; i<dates.length; i++)
{
data1 = filter1.filter(function(d) { return d.CONTACT_WEEK == dates[i] ;});
//console.log(data1);
var max = d3.max(data1, function(d) { return +d.WEEK_NUMBER ;});
//console.log(max);
data2 = data1.filter(function(d) { return d.WEEK_NUMBER == max ;});
var sum1 = d3.sum(data2, function(d) { return d.TOTCOUNT ;});
var sum2 = d3.sum(data2, function(d) { return d.DECAY_CNT ;});
console.log(sum1);
var decay = sum2/sum1 * 100 ;
console.log(decay);
}
第一步是确定日期的唯一值 (contact_week) - 我该如何在 reduce 函数中执行此操作,因为它已经是一个遍历数据的 for 循环?
我想对于 max 等,我们可以使用 reductio 或评论中提到的其他一些逻辑,但我并没有真正得到approach/design 在这里
approach/solutions 中的任何帮助将不胜感激。
更新2:
尝试使用 reductio js
的新方法
数据说明:
我的数据中有几列 - contact_week(日期); week_number (数字 - -4 到 6) ; decay_cnt(整数);总数(整数);持续时间(序数值 - 之前、期间和 post);
现在,我需要计算一个叫做 decay % 的百分比,计算方法如下:
对于每个唯一 contact_week,找到 week_number 的最大值,现在对于这个过滤后的数据集,计算总和 (decay_cnt) / 总和 (totcount)
这必须绘制在条形图中,其中 x 轴是持续时间,度量 - 衰减百分比是 y 轴
为了计算单个日期的周数最大值,我现在绘制了一个条形图,x 轴为 contact_week,y 轴为 week_number 的最大值-轴。
我如何获得我需要的图表?
代码:
dateDimension2 = ndx.dimension(function(d) {return d.CONTACT_WEEK ;});
decayGroup = reductio().max(function (d) { return d.WEEK_NUMBER; })(dateDimension2.group());
chart2
.width(500)
.height(200)
.x(d3.scale.ordinal())
//.x(d3.scale.ordinal().domain(["DURING","POST1"]))
.xUnits(dc.units.ordinal)
//.xUnits(function(){return 10;})
//.brushOn(false)
.yAxisLabel("Decay (in %)")
.dimension(dateDimension)
.group(decayGroup)
.gap(10)
.elasticY(true)
//.yAxis().tickValues([0, 5, 10, 15])
//.title(function(d) { return d.key + ": " + d3.round(d.value.new_count,2); })
/*.valueAccessor(function (p) {
//return p.value.count > 0 ? (p.value.dec_total / p.value.new_count) * 100 : 0;
return p.value.decay ;
})*/
.valueAccessor(function(d) { return d.value.max; })
.on('renderlet', function(chart) {
chart.selectAll('rect').on("click", function(d) {
console.log("click!", d);
});
})
.yAxis().ticks(5);
任何 approach/suggestions 将不胜感激
我认为解决方案主要在于假 groups/dimensions 和 reduction js 结合的方法。欢迎任何替代方案!
我刚刚为这类问题添加了a FAQ and an example。
正如那里所解释的那样,这个想法是维护一个属于每个 bin 的行数组,因为 crossfilter doesn't provide access to that yet。一旦我们得到实际的行,您的计算几乎与您现在所做的相同,除了 crossfilter 会为您跟踪周列表。
因此您可以使用示例中的这些函数:
function groupArrayAdd(keyfn) {
var bisect = d3.bisector(keyfn);
return function(elements, item) {
var pos = bisect.right(elements, keyfn(item));
elements.splice(pos, 0, item);
return elements;
};
}
function groupArrayRemove(keyfn) {
var bisect = d3.bisector(keyfn);
return function(elements, item) {
var pos = bisect.left(elements, keyfn(item));
if(keyfn(elements[pos])===keyfn(item))
elements.splice(pos, 1);
return elements;
};
}
function groupArrayInit() {
return [];
}
您的记录中需要有一个唯一的键,以便可以可靠地添加和删除它们。我假设您的记录有一个 ID
字段。
像这样定义你的周维度和组:
var weekDimension = ndx.dimension(function(d) {return d.CONTACT_WEEK ;}),
id_function = function(r) { return r.ID; },
weekGroup = weekDimension.group().reduce(groupArrayAdd(id_function), groupArrayRemove(id_function), groupArrayInit);
然后计算指标的最有效时间是在需要时,在值访问器中。因此,您可以使用您在问题中发布的代码的核心来定义您的值访问器。
(当然,这段代码未经测试,因为我不知道你的数据。)
var calculateDecay = function(kv) {
// kv.value has the array produced by the reduce functions.
var data1 = kv.value;
var max = d3.max(data1, function(d) { return +d.WEEK_NUMBER ;});
data2 = data1.filter(function(d) { return d.WEEK_NUMBER == max ;});
var sum1 = d3.sum(data2, function(d) { return d.TOTCOUNT ;});
var sum2 = d3.sum(data2, function(d) { return d.DECAY_CNT ;});
var decay = sum2/sum1 * 100 ;
return decay;
}
chart.valueAccessor(calculateDecay);
我正在尝试使用自定义缩减(reduceAdd、reduceRemove 等)创建一个用于放入 dc.js 的变量,但我不知道如何对其进行编码。
我在这些 reduce 函数之外编写了函数,现在必须在 reduce 函数内部复制相同的函数,以便对绘制的图形使用相同的函数。为外部reduce函数编写的逻辑和代码如下
逻辑:对于每个唯一的 contact_week 可用(日期),找到 week_number 的最大值,然后求和 TOTCOUNT 变量和 DECAY_CNT 变量并计算百分比(DECAY_CNT/ TOTCOUNT) .
这里是没有使用crossfilter的原始代码:
//Decay % logic
var dates = d3.map(filter1,function(d) { return d.CONTACT_WEEK;}).keys() ;
console.log(dates);
var sum1,sum2 = 0;
for(var i=0; i<dates.length; i++)
{
data1 = filter1.filter(function(d) { return d.CONTACT_WEEK == dates[i] ;});
//console.log(data1);
var max = d3.max(data1, function(d) { return +d.WEEK_NUMBER ;});
//console.log(max);
data2 = data1.filter(function(d) { return d.WEEK_NUMBER == max ;});
var sum1 = d3.sum(data2, function(d) { return d.TOTCOUNT ;});
var sum2 = d3.sum(data2, function(d) { return d.DECAY_CNT ;});
console.log(sum1);
var decay = sum2/sum1 * 100 ;
console.log(decay);
}
第一步是确定日期的唯一值 (contact_week) - 我该如何在 reduce 函数中执行此操作,因为它已经是一个遍历数据的 for 循环?
我想对于 max 等,我们可以使用 reductio 或评论中提到的其他一些逻辑,但我并没有真正得到approach/design 在这里
approach/solutions 中的任何帮助将不胜感激。
更新2:
尝试使用 reductio js
的新方法数据说明:
我的数据中有几列 - contact_week(日期); week_number (数字 - -4 到 6) ; decay_cnt(整数);总数(整数);持续时间(序数值 - 之前、期间和 post);
现在,我需要计算一个叫做 decay % 的百分比,计算方法如下: 对于每个唯一 contact_week,找到 week_number 的最大值,现在对于这个过滤后的数据集,计算总和 (decay_cnt) / 总和 (totcount)
这必须绘制在条形图中,其中 x 轴是持续时间,度量 - 衰减百分比是 y 轴
为了计算单个日期的周数最大值,我现在绘制了一个条形图,x 轴为 contact_week,y 轴为 week_number 的最大值-轴。 我如何获得我需要的图表?
代码:
dateDimension2 = ndx.dimension(function(d) {return d.CONTACT_WEEK ;});
decayGroup = reductio().max(function (d) { return d.WEEK_NUMBER; })(dateDimension2.group());
chart2
.width(500)
.height(200)
.x(d3.scale.ordinal())
//.x(d3.scale.ordinal().domain(["DURING","POST1"]))
.xUnits(dc.units.ordinal)
//.xUnits(function(){return 10;})
//.brushOn(false)
.yAxisLabel("Decay (in %)")
.dimension(dateDimension)
.group(decayGroup)
.gap(10)
.elasticY(true)
//.yAxis().tickValues([0, 5, 10, 15])
//.title(function(d) { return d.key + ": " + d3.round(d.value.new_count,2); })
/*.valueAccessor(function (p) {
//return p.value.count > 0 ? (p.value.dec_total / p.value.new_count) * 100 : 0;
return p.value.decay ;
})*/
.valueAccessor(function(d) { return d.value.max; })
.on('renderlet', function(chart) {
chart.selectAll('rect').on("click", function(d) {
console.log("click!", d);
});
})
.yAxis().ticks(5);
任何 approach/suggestions 将不胜感激
我认为解决方案主要在于假 groups/dimensions 和 reduction js 结合的方法。欢迎任何替代方案!
我刚刚为这类问题添加了a FAQ and an example。
正如那里所解释的那样,这个想法是维护一个属于每个 bin 的行数组,因为 crossfilter doesn't provide access to that yet。一旦我们得到实际的行,您的计算几乎与您现在所做的相同,除了 crossfilter 会为您跟踪周列表。
因此您可以使用示例中的这些函数:
function groupArrayAdd(keyfn) {
var bisect = d3.bisector(keyfn);
return function(elements, item) {
var pos = bisect.right(elements, keyfn(item));
elements.splice(pos, 0, item);
return elements;
};
}
function groupArrayRemove(keyfn) {
var bisect = d3.bisector(keyfn);
return function(elements, item) {
var pos = bisect.left(elements, keyfn(item));
if(keyfn(elements[pos])===keyfn(item))
elements.splice(pos, 1);
return elements;
};
}
function groupArrayInit() {
return [];
}
您的记录中需要有一个唯一的键,以便可以可靠地添加和删除它们。我假设您的记录有一个 ID
字段。
像这样定义你的周维度和组:
var weekDimension = ndx.dimension(function(d) {return d.CONTACT_WEEK ;}),
id_function = function(r) { return r.ID; },
weekGroup = weekDimension.group().reduce(groupArrayAdd(id_function), groupArrayRemove(id_function), groupArrayInit);
然后计算指标的最有效时间是在需要时,在值访问器中。因此,您可以使用您在问题中发布的代码的核心来定义您的值访问器。
(当然,这段代码未经测试,因为我不知道你的数据。)
var calculateDecay = function(kv) {
// kv.value has the array produced by the reduce functions.
var data1 = kv.value;
var max = d3.max(data1, function(d) { return +d.WEEK_NUMBER ;});
data2 = data1.filter(function(d) { return d.WEEK_NUMBER == max ;});
var sum1 = d3.sum(data2, function(d) { return d.TOTCOUNT ;});
var sum2 = d3.sum(data2, function(d) { return d.DECAY_CNT ;});
var decay = sum2/sum1 * 100 ;
return decay;
}
chart.valueAccessor(calculateDecay);