我正在使用 dc.js
、crossfilter.js
和 d3.js
生成条形图。
条形图表示信用卡交易的数据。它绘制了交易数量(y 轴)与交易金额(x 轴)的关系图。
看起来像这样:
数据数组基本上是这样的:
[
...
{
txn_id: 1,
txn_amount: 20
},
...
]
数据根据不同的商家等而变化很大,我无法对分布做出任何假设。
如您所见,由于数据本身的原因,这张图并不是那么有用。在这种情况下,有 1 笔交易 -$7500
和 2
大约 $7500
。
在其他金额之间,但大多数交易都集中在 $0 - $100
附近,您可以在其中看到峰值。
不幸的是,差异太大,您甚至看不到频率较低的交易金额的条形图。
这answer看起来很近,但又不完全。
我真正想做的是将 x 轴刻度分成 10 个大小合理的 block ,这些 block 合理地对交易金额进行分组,以使图表更有用。
例如,在这种情况下,平均交易金额为 $20
。最小值和最大值分别为 -$7500
和 $7500
所以在这个特定的示例中,我可能希望将 x 轴这样分块:
Bin 1: -$1000 >= transaction amount
Bin 2: -$100 >= transaction amount > -$1000
Bin 3: -$50 >= transaction amount > -$100
Bin 4: $0 >= transaction amount > -$50
Bin 5: $15 >= transaction amount > $0
Bin 6: $25 >= transaction amount > $15
Bin 7: $40 >= transaction amount > $25
Bin 8: $100 >= transaction amount > $40
Bin 9: $1000 >= transaction amount > $100
Bin 10: transaction amount > $1000
( block /bin 大小变得越来越小,越接近我们得到的平均值)。
不可否认,我已经很久没有认真研究过统计学了,所以我很生疏。但似乎我将数据分成 bin/chuck 的方式与我的数据的标准偏差有很大关系。
我想我对我想要的东西有很好的感觉,我只是对如何使用 d3.js
(d3.mean()
, d3.quantile()
?) 和 dc.js
来获取类似于我所描述的直方图。
那么正确的方法是什么,或者我应该使用哪些库来:
- 根据任意给定的数据集创建 10 个“合理”大小的 bin
- 将数据分组到这些容器中(实际上,这部分应该非常简单)
就物理间距直方图的 x 轴而言,我认为刻度的间距不均匀是没有必要或不希望的(因此它可能不再是直方图)。
尽管 block 大小不相等,但我更希望刻度保持均匀间隔。我会确保适本地标记蜱虫。
任何指向正确方向的指示都将不胜感激。
更新:
看来 d3.js
像往常一样比我领先几步,并且已经得到了我的支持。我相信我可以使用 d3.scale.quantile()
将 x 轴分成 10 个分位数(十分位数)。事实上,我已经设置了我的分位数标度并且它似乎在做正确的事情,当我将数字直接输入分位数标度函数(通过 JS 控制台)时它输出正确的桶(在 10 个桶中)。
但不幸的是,我的图表仍然一团糟。这是我的代码:
var datum = crossfilter(data),
amount = datum.dimension(function(d) { return +d.txn_amount; }),
amounts = amount.group();
amountsChart = dc.barChart("#dc-amounts-chart");
amountsChart
.width(defaultWidth)
.height(defaultHeight)
.margins({top: 20, right: 20, bottom: 20, left: 50})
.dimension(amount)
.group(amounts)
.centerBar(true)
.gap(5)
.elasticY(true)
.x(d3.scale.quantile().domain(amounts.all().map(function(d) {
// d.key is the transaction dollar amount,
// d.value is the number of transactions at that amount
return d.key;
}))
.range([0,1,2,3,4,5,6,7,8,9]));
amountsChart.yAxis().ticks(5);
dc.renderAll();
以及生成的图表:
我想我已经接近了,但仍然不确定我在哪里走错了路。
最佳答案
您可以使用离群值测试来 trim 您的离群值,然后将它们添加回极端容器中。我还将这些容器上的文本更改为 y,但这可以通过将一组自定义刻度传递到轴来轻松完成。
我使用 Chauvenet's criterion 模拟了一个示例,许多离群值测试之一。我最初想使用 Grubbs 测试(或者更好的是多重 Grubbs Beck 测试),但要对其进行编码需要做一些工作。 Chauvenet 的标准非常简单,它假设任何与均值相差 m 个标准差的值都是异常值。
我把这些放在一起了 here函数是:
function chauvenet (x) {
var dMax = 3;
var mean = d3.mean(x);
var stdv = Math.sqrt(variance(x));
var counter = 0;
var temp = [];
for (var i = 0; i < x.length; i++) {
if(dMax > (Math.abs(x[i] - mean))/stdv) {
temp[counter] = x[i];
counter = counter + 1;
}
};
return temp
}
术语都很明显,dMax 是标准差的数量,mean 是平均值,stdv 是标准差(或方差的平方根)。
请注意,我没有将异常值添加回直方图中,但这应该很容易做到。
关于javascript - 为高度偏斜的数据生成直方图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19288865/