Crossfilter数据集的逐年统计数据 [英] Year over Year Stats from a Crossfilter Dataset

查看:74
本文介绍了Crossfilter数据集的逐年统计数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Crossfilter-DC驱动的仪表板中提取逐年统计数据

I want to pull out Year over Year stats in a Crossfilter-DC driven dashboard

2017年同比是2017年的总单位除以2016年的总单位。

2017 YoY is the total units in 2017 divided by the total units in 2016.

我正在使用 DC.js (因此使用的是 D3。 js & Crossfilter )创建一个交互式仪表板,该仪表板也可用于更改其呈现的数据。

I'm using DC.js (and therefore D3.js & Crossfilter) to create an interactive Dashboard that can also be used to change the data it's rendering.

我有数据,尽管数据更宽(除日期和数量外还有〜6个其他属性:大小,颜色等...销售数据),但归结为以下对象:

I have data, that though wider (has ~6 other attributes in addition to date and quantity: size, color, etc...sales data), boils down to objects like:

[
 { date: 2017-12-7, quantity: 56,  color: blue  ...},
 { date: 2017-2-17, quantity: 104, color: red   ...},
 { date: 2016-12-7, quantity: 60,  color: red   ...},
 { date: 2016-4-15, quantity: 6,   color: blue  ...},
 { date: 2017-2-17, quantity: 10,  color: green ...},
 { date: 2016-12-7, quantity: 12,  color: green ...}
  ...
]

我正在为每个属性显示一个行图表,以便您可以按颜色,大小等查看总计。人们将使用这些图表中的每个图表,以查看该属性的总计,并通过仅过滤进行细化颜色,颜色,大小,大小等。此设置(相对)简单明了,是DC的用途。

I'm displaying one rowchart per attribuet such that you can see the totals by color, size, etc. People would use each of these charts to be able to see the totals by that attribute and drill into the data by filtering by just a color, or a color and a size, or a size, etc. This setup is all (relatively) straight forward and kind of what DC is made for.

但是,现在我想添加一些同比数据,这样我就可以显示一个条形图,其中x轴为年份,y轴为YoY值(例如同比2019 =单位2019 /单位2018)。我还希望按季度和月份进行相同操作,以便可以看到2019年3月同比= 2019年3月单位/ 2018年3月单位(季度也是如此)。

However, now I'd like to add some YoY stats such that I can show a barchart with x-axis as the years, and the y-axis as the YoY values (ex. YoY-2019 = Units-2019 / Units-2018). I'd also like to do the same by quarter and month such that I could see YoY Mar-2019 = Units-Mar-2019 / Units-Mar-2018 (and the same for quarter).

我有一个年份维度和总数量

I have a year dimension and sum quantity

var yearDim = crossfilterObject.dimension(_ => _.date.getFullYear());
var quantityGroup = yearDim.group.reduceSum(_ => _.quantity);

我不知道如何在漂亮的漂亮DC中进行逐年计算.js-way。

I can't figure out how to do the Year over Year calc though in the nice, beautiful DC.js-way.

1年级

添加年份+ 1的另一个维度。尽管如此,我并没有真正得到进一步的帮助,因为我得到的只是两个维度,我想对其年份组进行划分...

Add another dimension that's year + 1. I didn't' really get any further though because all I get out of it are two dimensions whose year groups I want to divide ... but am not sure how.

var yearPlusOneDim = crossfilterObject.dimension(_ => _.date.getFullYear() + 1);

在视觉上,我可以分别画出两者,并且从概念上讲,我想做什么:将YearDim中的2017年数字除以YearPlusOneDim中的2017年数字(实际上是2016年数字)。但是就我所了解的一个概念而言。

Visually I can graph the two separately and I know, conceptually, what I want to do: which is divide the 2017 number in yearDim by the 2017 number in YearPlusOneDim (which, in reality, is the 2016 number). But "as a concept is as far as I got on this one.

放弃DC绘图

我总是可以使用yearDim的数量组来获取值的数组,然后可以将其输入到正常的D3.js图中。

I could always use the yearDim's quantity group to get the array of values, which I could then feed into a normal D3.js graph.

var annualValues = quantityGroup.all();
console.log(annualValues);
// output = [{key: 2016, value: 78}, {key: 2017, value: 170}]
// example data from the limited rows listed above

这听起来像是一个骇人听闻的解决方案,注定会失败,而不能从所有快速而动态的DC更新中受益。

But this feels like a hacky solution that's bound to fail and not benefit from all the rapid and dynamic DC updating.

推荐答案

如@Ethan所说,您也可以使用值访问器,但随后您必须查看上一次每次访问值时的时间-因此您可能必须保留一个额外的表。对于假组,您只需要将此表放在<$ c主体中$ c> .all()函数。

As @Ethan says, you could also use a value accessor, but then you'd have to look up the previous year each time a value is accessed - so you'd probably have to keep an extra table around. With a fake group, you only need this table in the body of your .all() function.

下面是伪造的组的简要示意图:

Here's a quick sketch of what the fake group might look like:

function yoy_group(group) {
    return {
        all: function() {
            // index all values by date
            var bydate = group.all().reduce(function(p, kv) {
                p[kv.key.getTime()] = kv.value;
                return p;
            }, {});
            // for any key/value pair which had a value one year earlier,
            // produce a new pair with the ratio between this year and last
            return group.all().reduce(function(p, kv) {
                var date = d3.timeYear.offset(kv.key, -1);
                if(bydate[date.getTime()])
                    p.push({key: kv.key, value: kv.value / bydate[date.getTime()]});
                return p;
            }, []);
        }
    };
}

这个想法很简单:首先按日期索引所有值。然后,在生成键/值对数组时,向上查找每个键/值对是否一年前有值。如果是这样,将一对插入结果中(否则将其删除)。

The idea is simple: first index all the values by date. Then when producing the array of key/value pairs, look each one up to see if it had a value one year earlier. If so, push a pair to the result (otherwise drop it).

此方法适用于日期已四舍五入的任何带有日期键的组。

This should work for any date-keyed group where the dates have been rounded.

请注意使用 Array.reduce 在几个地方。这是crossfilter的 group.reduce 的精神祖先-它采用的函数具有与reduce-add函数相同的签名,并且具有初始值(而不是函数)和产生单个值。它没有像交叉过滤器那样对更改做出反应,而是仅循环遍历该数组一次。当您要从数组中生成对象或生成与原始对象不同大小的数组时,此功能很有用。

Note the use of Array.reduce in a couple of places. This is the spiritual ancestor of crossfilter's group.reduce - it takes a function which has the same signature as the reduce-add function, and an initial value (not a function) and produces a single value. Instead of reacting to changes like the crossfilter one does, it just loops over the array once. It's useful when you want to produce an object from an array, or produce an array of different size from the original.

此外,当按日期索引对象时,我使用 Date.getTime()获取日期的数字表示形式。否则,日期将强制为可能不准确的字符串表示形式。可能对于此应用程序,可以跳过 .getTime(),但我习惯总是始终比较日期。

Also, when indexing an object by a date, I use Date.getTime() to fetch the numeric representation of the date. Otherwise the date coerces to a string representation which may not be exact. Probably for this application it would be okay to skip .getTime() but I'm in the habit of always comparing dates exactly.

演示小提琴 dc.js主页上的示例。

Demo fiddle of YOY trade volume in the data set used by the stock example on the main dc.js page.

这篇关于Crossfilter数据集的逐年统计数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆