d3.nest 详解

d3.nest可以分组数据

在进行数据分析时Grouping data是一个很重要的能力 .通常,我们需要将数据按照某个类别进行打散,并查找和统计每个组的具体细节。

D3 包括强大的d3.nest 功能,可以通过极小量的代码构造分组。

Nest 基础

用户来决定这个嵌套多少层。
跟很多GROUP_BY概念有点不同,其中只允许有嵌套一个级别。

例如,我们有如下的 CSV 格式文件 “expenses”:

name,amount,date
jim,34.0,11/12/2015
carl,120.11,11/12/2015
jim,45.0,12/01/2015
stacy,12.00,01/04/2016
stacy,34.10,01/04/2016
stacy,44.80,01/05/2016

转换为对象数组:

var expenses = [{"name":"jim","amount":34,"date":"11/12/2015"},
  {"name":"carl","amount":120.11,"date":"11/12/2015"},
  {"name":"jim","amount":45,"date":"12/01/2015"},
  {"name":"stacy","amount":12.00,"date":"01/04/2016"},
  {"name":"stacy","amount":34.10,"date":"01/04/2016"},
  {"name":"stacy","amount":44.80,"date":"01/05/2016"}
];

然后,由我们决定以什么样的方式将这些数据切片
我们首先以Name

var expensesByName = d3.nest()
  .key(function(d) { return d.name; })
  .entries(expenses);

用的D3.js

结果为:

expensesByName = [
  {"key":"jim","values":[
    {"name":"jim","amount":34,"date":"11/12/2015"},
    {"name":"jim","amount":45,"date":"12/01/2015"}
  ]},
  {"key":"carl","values":[
    {"name":"carl","amount":120.11,"date":"11/12/2015"}
  ]},
  {"key":"stacy","values":[
    {"name":"stacy","amount":12.00,"date":"01/04/2016"},
    {"name":"stacy","amount":34.10,"date":"01/04/2016"},
    {"name":"stacy","amount":44.80,"date":"01/05/2016"}
  ]}
];

expensesByName 为一个对象数组. 用key function来组成value,每个对象都有一个key属性和value属性
这些entries的values属性是一个数组,是所有的原始数据对象。

概述Groups

嵌套的结构非常有利于可视化数据,特别是分析应用。

d3.rollup , 提供一个功能来获取每个组的values,并产生新的数值。这使得group功能非常灵活。

如下面的例子获取每个name的总数:

var expensesCount = d3.nest()
  .key(function(d) { return d.name; })
  .rollup(function(v) { return v.length; })
  .entries(expenses);
console.log(JSON.stringify(expensesCount));
=> [{"key":"jim","values":2},{"key":"carl","values":1},{"key":"stacy","values":3}]

用来的values值由rollup函数产生的值所所代替。 而name不变。

另外一个例子获取每个人的平均金额:

var expensesAvgAmount = d3.nest()
  .key(function(d) { return d.name; })
  .rollup(function(v) { return d3.mean(v, function(d) { return d.amount; }); })
  .entries(expenses);
console.log(JSON.stringify(expensesAvgAmount));
=> [{"key":"jim","values":39.5},{"key":"carl","values":120.11},{"key":"stacy","values":30.3}]

很棒吧?rollup中还可以使用多个操作:

var expenseMetrics = d3.nest()
  .key(function(d) { return d.name; })
  .rollup(function(v) { return {
    count: v.length,
    total: d3.sum(v, function(d) { return d.amount; }),
    avg: d3.mean(v, function(d) { return d.amount; })
  }; })
  .entries(expenses);
console.log(JSON.stringify(expenseMetrics));
=> [{"key":"jim","values":{"count":2,"total":79,"avg":39.5}},
 {"key":"carl","values":{"count":1,"total":120.11,"avg":120.11}},
 {"key":"stacy","values":{"count":3,"total":90.9,"avg":30.3}}]

输出Map

数组可以输出为Map的数据结果,或者使用forEach来处理迭代和合计任务。d3.nest可以返回一个对象(或者map),如下:

var expensesTotal = d3.nest()
  .key(function(d) { return d.name; })
  .rollup(function(v) { return d3.sum(v, function(d) { return d.amount; }); })
  .map(expenses);
console.log(JSON.stringify(expensesTotal));
=> {"jim":79,"carl":120.11,"stacy":90.9}

多级嵌套

nest还可以多级嵌套

可以进一步key操作,如下,每个人的花费总计,以及日期:

var expensesTotalByDay = d3.nest()
  .key(function(d) { return d.name; })
  .key(function(d) { return d.date; })
  .rollup(function(v) { return d3.sum(v, function(d) { return d.amount; }); })
  .map(expenses);
console.log(JSON.stringify(expensesTotalByDay));
=> {"jim":{"11/12/2015":34,"12/01/2015":45},
 "carl":{"11/12/2015":120.11},
 "stacy":{"01/04/2016":46.1,"01/05/2016":44.8}}

rollup是应用在子分组中。
nest.key的先后顺序决定了分组的方式. 如果交换name和date:

var expensesTotalByDay = d3.nest()
  .key(function(d) { return d.date; })
  .key(function(d) { return d.name; })
  .rollup(function(v) { return d3.sum(v, function(d) { return d.amount; }); })
  .map(expenses);
console.log(JSON.stringify(expensesTotalByDay));
=> {"11/12/2015":{"jim":34,"carl":120.11},
 "12/01/2015":{"jim":45},
 "01/04/2016":{"stacy":46.1},
 "01/05/2016":{"stacy":44.8}}

衍生 Key Values

我们可以自己指定keyvalue,例如,我们想知道每年的总数,我们可以仅仅操作date,来获取年号:

var expensesByYear = d3.nest()
  .key(function(d) { return d.date.split("/")[2]; })
  .rollup(function(v) { return d3.sum(v, function(d) { return d.amount; }); })
  .map(expenses);
console.log(JSON.stringify(expensesByYear));
=> {"2015":199.11,"2016":90.9}
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值