gpt4 book ai didi

javascript - dc.js使用两个没有简单尺寸和第二分组阶段的化约器

转载 作者:行者123 更新时间:2023-11-29 20:51:26 25 4
gpt4 key购买 nike

我在这篇文章中回覆之后的简短问题:
dc.js Box plot reducer using two groups
只是想尽我最大的能力去了解减速器,以及如何过滤和收集数据,所以我将首先逐步理解。

资料格式:

{
"SSID": "eduroam",
"identifier": "Client",
"latitude": 52.4505,
"longitude": -1.9361,
"mac": "dc:d9:16:##:##:##",
"packet": "PR-REQ",
"timestamp": "2018-07-10 12:25:26",
"vendor": "Huawei Technologies Co.Ltd"
}


(1)使用以下命令应产生键值对的输出数组(键MAC地址和所连接网络的值计数):

var MacCountsGroup = mac.group().reduce(
function (p, v) {
p[v.mac] = (p[v.mac] || 0) + v.counter;
return p;
},
function (p, v) {
p[v.mac] -= v.counter;
return p;
},
function () {
return {}; // KV Pair of MAC -> Count
}
);


(2)然后,为了使用该对象,必须将其展平,以便可以按如下所示将其传递到图表:

function flatten_object_group(group) {
return {
all: function () {
return group.all().map(function (kv) {
return {
key: kv.key,
value: Object.values(kv.value).filter(function (v) {
return v > 0;
})
};
});
}
};
}

var connectionsGroup = flatten_object_group(MacCountsGroup);


(3)然后,我将mac作为饼图维,并将connectionsGroup作为组传递。这会根据我的数据集向图表返回大约50,000个切片的图表。

var packetPie = dc.pieChart("#packetPie");
packetPie
.height(495)
.width(350)
.radius(180)
.renderLabel(true)
.transitionDuration(1000)
.dimension(mac)
.ordinalColors(['#07453E', '#145C54', '#36847B'])
.group(connectionsGroup);


enter image description here

没问题,我会继续进行。

(4)现在,我想按第一个reducer给出的值进行分组,即我想将所有mac地址与1个网络连接,2个网络连接等组合在一起作为切片。

如何将其作为“网络连接”的维度?我该如何生成源数据中不存在的,由mac生成的汇总数据?

还是这需要在第一化简器和展平之间使用中间函数来组合来自第一化简器的所有值?

最佳答案

您无需完成所有操作即可获取mac地址的饼图。

在第1-3点中有一些错误的理解,我想我将首先解决。看来您从上一个问题复制并粘贴了代码,所以我不确定是否有帮助。

(1)如果您使用的是Mac地址,则将其减小将不会有任何进一步的影响。最初的想法是按供应商进行维度/分组,然后减少每个mac地址的数量。这种减少将按mac地址分组,然后进一步计算每个bin中每个mac地址的实例,因此它只是一个带有一个键的对象。它将产生键值对的映射,例如

{key: 'MAC-123', value: {'MAC-123': 12}}


(2)这将使对象在值内变平,放下键并仅产生一个计数数组

{key: 'MAC-123', value: [12]}


(3)由于饼图期望简单的键/值对,其值是一个数字,因此对获取数组 [12]之类的值可能不满意。该值可能被强制为 NaN

(4)好的,这是真正的问题,实际上并不像您先前的问题那么简单。我们对箱形图很轻松,因为数据中存在“维度”(用交叉过滤器来说,就是您过滤和分组的键)。

让我们忘记以上第1-3点中的错误线索,并从第一原则开始。

无法查看数据的单个行并确定它是否属于“具有1个连接”,“具有2个连接”等类别,而无需查看其他内容。假定您希望能够单击在饼图中的切片上并过滤所有数据,我们将不得不寻找另一种实现方法。

但是首先让我们看一下如何生成“网络连接数”饼图。这稍微容易一些,但是据我所知,它确实需要真正的“双重减少”。

如果我们在mac维度上使用默认的缩减,我们将获得一个键/值对数组,其中键是mac地址,而值是该地址的连接数:

[
{
"key": "1c:b7:2c:48",
"value": 8
},
{
"key": "1c:b7:be:ef",
"value": 3
},
{
"key": "6c:17:79:03",
"value": 2
},
...


现在我们如何生成键/值数组,其中键是连接数,而值是该连接数的mac地址数组?

听起来像是鲜为人知的 Array.reduce的工作。此函数可能是Crossfilter的 group.reduce()的灵感来源,但它有点简单:它只是遍历一个数组,将每个值与最后一个的结果组合在一起。从数组生成对象非常好:

var value_keys = macPacketGroup.all().reduce(function(p, kv) {
if(!p[kv.value])
p[kv.value] = [];
p[kv.value].push(kv.key);
return p;
}, {});


大:

{
"1": [
"b8:1d:ab:d1",
"dc:d9:16:3a",
"dc:d9:16:3b"
],
"2": [
"6c:17:79:03",
"6c:27:79:04",
"b8:1d:aa:d1",
"b8:1d:aa:d2",
"dc:da:16:3d"
],


但是我们想要一个键/值对数组,而不是对象!

var key_count_value_macs = Object.keys(value_keys)
.map(k => ({key: k, value: value_keys[k]}));


太好了,看起来就像一个“真实团体”会产生什么:

[
{
"key": "1",
"value": [
"b8:1d:ab:d1",
"dc:d9:16:3a",
"dc:d9:16:3b"
]
},
{
"key": "2",
"value": [
"6c:17:79:03",
"6c:27:79:04",
"b8:1d:aa:d1",
"b8:1d:aa:d2",
"dc:da:16:3d"
]
},
...


将所有内容包装在“伪造的组”中,当要求生成 .all()时,将查询原始组并执行上述转换:

function value_keys_group(group) {
return {
all: function() {
var value_keys = group.all().reduce(function(p, kv) {
if(!p[kv.value])
p[kv.value] = [];
p[kv.value].push(kv.key);
return p;
}, {});
return Object.keys(value_keys)
.map(k => ({key: k, value: value_keys[k]}));
}
}
}


现在我们可以绘制饼图了!唯一有趣的是,值访问器应查看每个值的数组长度(而不是假设值只是一个数字):

packetPie
// ...
.group(value_keys_group(macPacketGroup))
.valueAccessor(kv => kv.value.length);


packet pie

Demo fiddle

但是,单击切片将不起作用。一分钟后,我将再次介绍该内容-只想先单击“保存”!

第2部分:基于计数的过滤

正如我在开始时所说的那样,不可能创建一个交叉过滤器维,该维将根据连接数进行过滤。这是因为交叉过滤器始终需要查看每一行,并仅基于该行中的信息来确定它是否属于组或过滤器。

如果此时添加另一个图表,然后尝试单击一个切片 everything in the other charts will disappear。这是因为密钥现在是计数,并且计数是无效的mac地址,因此我们要告诉它过滤到不存在的密钥。

但是,我们显然可以按mac地址进行过滤,而且我们也知道每个计数的mac地址!所以这还不错。它只需要一个 filterHandler

虽然,嗯,在制作假组时,我们似乎已经忘记了 value_keys。它隐藏在函数内部,然后放开。

这有点丑陋,但我们可以解决此问题:

function value_keys_group(group) {
var saved_value_keys;
return {
all: function() {
var value_keys = group.all().reduce(function(p, kv) {
if(!p[kv.value])
p[kv.value] = [];
p[kv.value].push(kv.key);
return p;
}, {});
saved_value_keys = value_keys;
return Object.keys(value_keys)
.map(k => ({key: k, value: value_keys[k]}));
},
value_keys: function() {
return saved_value_keys;
}
}
}


现在,每次调用 .all()(每次绘制饼形图)时,假组都会隐藏 value_keys对象。这不是一个好习惯(如果在 .value_keys()之前调用 undefined会返回 .all()),但是基于dc.js的工作方式是安全的。

这样,饼图的 filterHandler相对简单:

packetPie.filterHandler(function(dimension, filters) {
if(filters.length === 0)
dimension.filter(null);
else {
var value_keys = packetPie.group().value_keys();
var all_macs = filters.reduce(
(p, v) => p.concat(value_keys[v]), []);
dimension.filterFunction(k => all_macs.indexOf(k) !== -1);
}
return filters;
});


有趣的一行是对 Array.reduce的另一个调用。此函数对于从另一个数组生成一个数组也很有用,在这里我们仅使用它来连接所有选定切片(连接计数)中的所有值(mac地址)。

现在我们有一个工作的过滤器。将其与最后一个问题的箱形图组合起来没有太大意义,但是 the new fiddle演示了基于连接数的过滤确实有效。

第三部分:零呢?

通常情况下,交叉过滤器认为值零的bin仍然存在,因此我们需要 "remove the empty bins"。但是,在这种情况下,我们为第一个假组添加了非标准方法,以便进行过滤。 (我们可以在那里使用一个全局变量,但是全局变量是凌乱的。)

因此,我们需要“通过” value_keys方法:

function remove_empty_bins_pt(source_group) {
return {
all:function () {
return source_group.all().filter(function(d) {
return d.key !== '0';
});
},
value_keys: function() {
return source_group.value_keys();
}
};
}
packetPie
.group(remove_empty_bins_pt(value_keys_group(macPacketGroup)))


另一个奇怪的是,我们正在过滤掉键零,而这就是一个字符串!

Demo fiddle!

或者,这是一个更好的解决方案!在传递到 value_keys_group之前进行bin过滤,然后我们可以使用普通的 remove_empty_bins

function remove_empty_bins(source_group) {
return {
all:function () {
return source_group.all().filter(function(d) {
//return Math.abs(d.value) > 0.00001; // if using floating-point numbers
return d.value !== 0; // if integers only
});
}
};
}
packetPie
.group(value_keys_group(remove_empty_bins(macPacketGroup)))


Yet another demo fiddle!!

关于javascript - dc.js使用两个没有简单尺寸和第二分组阶段的化约器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51677899/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com