【问题标题】:Generating histogram for highly skewed data为高度倾斜的数据生成直方图
【发布时间】:2013-10-17 19:20:19
【问题描述】:

我正在使用dc.jscrossfilter.jsd3.js 来生成条形图。

条形图表示信用卡交易的数据。它绘制了交易数量(y 轴)与交易金额(x 轴)的关系。

看起来像这样:

数据数组基本上是这样的:

[
  ...
  {
    txn_id: 1,
    txn_amount: 20
  },
  ...
]

根据不同的商家等,数据变化很大,我无法对分布做出任何假设。

正如您所见,由于数据本身的原因,该图表并没有那么有用。在这种情况下,-$75002 有 1 笔交易在 $7500 附近。

介于其他数量之间,但大多数交易都集中在 $0 - $100 附近,您可以在其中看到峰值。

不幸的是,差异太大,您甚至看不到不太频繁的交易金额的条形图。

这个answer 似乎很接近,但并不完全在那里。

我真正想做的是将 x 轴刻度分成 10 个大小合理的块,将交易金额合理地分组,以使图表更有用。

例如,假设在这种情况下平均交易金额为$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

(chunk/bin 大小越来越小,越接近我们得到的平均值)。

诚然,我已经很久没有认真研究过统计学了,所以我很生疏。但似乎我将数据分解成 bin/chuck 的方式与我的数据的标准偏差有很大关系。

我想我对我想要的东西有很好的感觉,我只是有点迷失如何使用 d3.js (d3.mean(), d3.quantile() ?) 和 dc.js 来获得类似于如何使用的直方图我已经描述过了。

那么正确的方法是什么,或者我应该使用哪些库:

  1. 根据任意给定的数据集创建 10 个“合理”大小的 bin
  2. 将数据分组到这些 bin 中(实际上,这部分应该很简单)

就物理间距直方图的 x 轴而言,我认为没有必要或不希望刻度的间距不均匀(因此它可能不再是直方图)。

尽管块大小不相等,但我希望刻度保持均匀间隔。我会确保适当地标记刻度。

任何正确方向的指针将不胜感激。

更新:

所以看起来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();

以及生成的图表:

我想我快到了,但仍然不确定我在哪里走错了路。

【问题讨论】:

标签: javascript d3.js statistics dc.js


【解决方案1】:

您可以使用异常值测试来剔除您的异常值,然后将它们重新添加到极端垃圾箱中。我还将这些箱子上的文本更改为 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 是标准差(或方差的平方根)。

请注意,我没有将异常值添加回直方图中,但这应该很容易做到。

【讨论】:

  • 感谢您的回答。这很棒。我可能最终会选择这条路线,因为它看起来完全合理。尽管我对图表的问题仍然感到困惑,因为理论上,将我的数据分成 10 个相等的十分位数(等于每个桶中的数据点数)应该可以解决问题。我可以看到我的分位数是正确的,但图表与分位数比例不匹配。
【解决方案2】:

如果 d3 给你带来困难..试试这个http://imaginea.github.com/uvCharts :) 你一定已经知道 nvd3

【讨论】:

  • 谢谢,看到另一个图表库很有趣。 d3 没有给我问题,而是 dc.js。我以前使用过 nvd3 并取得了很大的成功,但它们没有内置的交叉过滤器集成和过滤,这对我们来说非常重要。不幸的是,我们在这一点上已经投入了足够的资金,我暂时还没有看到我们切换图形库。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
相关资源
最近更新 更多