【问题标题】:Group array elements based on value and get median of other value根据值对数组元素进行分组并获取其他值的中位数
【发布时间】:2021-05-26 02:01:00
【问题描述】:

我正在尝试根据来自 Spotify audio analysis 的数据创建可视化。 以下是部分数据:

{
  ...
  "segments": [
    {
      "start": 0,
      "duration": 0.20934,
      "confidence": 1,
      "loudness_start": -60,
      "loudness_max_time": 0.06898,
      "loudness_max": -22.328,
      "loudness_end": 0,
      ...
    },
    {
      "start": 0.20934,
      "duration": 0.10907,
      "confidence": 0.772,
      "loudness_start": -35.399,
      "loudness_max_time": 0.01327,
      "loudness_max": -25.11,
      "loudness_end": 0,
      ...
    },
    ...
  ],
  ...
}

我想做什么:

  1. 根据起始值对这些段进行分组。示例:从第 0 秒到第 1 秒的所有片段都是一个组,从第 1 秒到第 2 秒的所有片段等等......
  2. 每个组都应该是一个包含所有值的新对象(例如,所有 loudness_max 值的中值、所有 loudness_start 值的中值等...)

我已经尝试过使用d3s 组和汇总函数,但到目前为止我无法让它工作。如何使用js/d3 实现这一目标?

我希望这个描述是可以理解的,在此先感谢您的帮助!

【问题讨论】:

    标签: javascript arrays d3.js


    【解决方案1】:

    一种方法是使用d3.bin()创建桶,并通过聚合函数映射桶以聚合属性,例如d3.median()

    d3.bin() 方法根据给定的分桶定义创建数据组(d3 称之为thresholds)。 d3.bin() 的输出与您输入的数据相同,但桶周围有数组。例如,在阈值 [0, 1, 2] 中分箱的数组 [0.2, 0.8, 1.2, 1.8] 变为 [ [0.2, 0.8], [1.2, 1.8] ]

    您可以使用d3.bin().value() 方法来指定一个访问器,在您的例子中是一个访问start 属性d => d.start 的函数。

    由于您希望阈值是整秒,因此需要进行一些预处理计算来计算阈值;我将在下面代码sn-p的cmets中解释它们:

        // Compute the max value of the data and round up to get the whole second.
        const maxValue = Math.ceil(d3.max(data, d=> d.start))
        
        // Define the bin thresholds (In your case, an array of whole seconds: 0, 1, ... , maxValue)
        const thresholds = d3.range(maxValue+1)
    
        // Define the min and max values of the buckets
        const domain = [0, maxValue]
        
        // Create the binner function 
        const binner = d3.bin().value(d=>d.start).thresholds(thresholds).domain(domain)
    
        // Bin the data
        const binned = binner(data)
        
        // Map each bin array and return
        const medians = binned.map(bin => {
            return {
              medianDuration: d3.median(bin, b=>b.duration),
              medianConfidence: d3.median(bin, b=>b.confidence),
                // ... The other properties repeat the same pattern
    
                /* You can also extract three additional values: the amount of data 
                in the bin, the start of the bin, and the end of the bin; */
              dataPoints: bin.length,
              bucketMin: bin.x0,
              bucketMax: bin.x1
          }
        })
    

    工作示例:

    const data = getData()
    const maxValue = Math.ceil(d3.max(data, d=> d.start))
    
    const thresholds = d3.range(maxValue+1)
    const domain = [0, maxValue]
    
    const binner = d3.bin().value(d=>d.start).thresholds(thresholds).domain(domain)
    const binned = binner(data)
    
    const medians = binned.map(bin => {
        return {
        medianDuration: d3.median(bin, b=>b.duration),
        dataPoints: bin.length,
        bucketMin: bin.x0,
        bucketMax: bin.x1
    
      }
    })
    
    console.log(medians)
    
    function getData() {
      return [{
          "start": 0.2,
          "duration": 0.20934,
    }, {
          "start": 0.8,
          "duration": 0.30934,
    },
    {
          "start": 1.2,
          "duration": 0.20934,
    },
    {
          "start": 1.8,
          "duration": 0.10934,
    },
    {
          "start": 2.2,
          "duration": 0.30934,
    },
    {
          "start": 2.8,
          "duration": 0.40934,
    }]
    }
    <script src="https://d3js.org/d3.v6.min.js"></script>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-15
      • 1970-01-01
      相关资源
      最近更新 更多