【问题标题】:Smoothing out values of an array平滑数组的值
【发布时间】:2015-12-23 16:17:51
【问题描述】:

如果我有一个数字数组,例如 [3, 5, 0, 8, 4, 2, 6],有没有办法“平滑”这些值,使它们彼此更接近并显示更少方差?

我已经研究了使用称为高斯函数的方法对数据进行窗口化处理,该函数是 1 维情况,这是我的数组,但在实现它时遇到了麻烦。 This thread 似乎正好解决了我需要的问题,但我不明白用户 naschilling(第二篇文章)是如何得出高斯矩阵值的。

上下文:我正在开发一个音乐波形发生器(借鉴 SoundCloud 的设计),它将歌曲在时间 t 的振幅映射到相应的条形高度。不幸的是,有很多噪音,当程序映射一个微小的幅度导致高度突然降低时,它看起来特别难看。我基本上想平滑条形高度,这样它们就不会那么变化了。

我使用的语言是 Javascript。

编辑:抱歉,让我更具体地说明“平滑”这些值。根据上面链接的线程,用户拿了一个数组

[10.00, 13.00, 7.00, 11.00, 12.00, 9.00, 6.00, 5.00]

并使用高斯函数将其映射到

[ 8.35,  9.35, 8.59,  8.98,  9.63, 7.94, 5.78, 7.32]

请注意这些数字彼此之间的距离如何。

编辑 2:成功了!感谢用户 Awal Garg 的算法,结果如下:

没有平滑 一些平滑 最大平滑

编辑 3:这是我在 JS 中的最终代码。我对其进行了调整,以便数组的第一个和最后一个元素能够通过 环绕 数组而不是调用自身来找到它的邻居。

var array = [10, 13, 7, 11, 12, 9, 6, 5];

function smooth(values, alpha) {
    var weighted = average(values) * alpha;
    var smoothed = [];
    for (var i in values) {
        var curr = values[i];
        var prev = smoothed[i - 1] || values[values.length - 1];
        var next = curr || values[0];
        var improved = Number(this.average([weighted, prev, curr, next]).toFixed(2));
        smoothed.push(improved);
    }
    return smoothed;
}

function average(data) {
    var sum = data.reduce(function(sum, value) {
        return sum + value;
    }, 0);
    var avg = sum / data.length;
    return avg;
}

smooth(array, 0.85);

【问题讨论】:

  • 我不确定我理解你的意思平滑值

标签: javascript arrays smoothing


【解决方案1】:

有趣的问题!

平滑值的算法显然可以改变很多,但这是我的看法:

"use strict";
var array = [10, 13, 7, 11, 12, 9, 6, 5];

function avg (v) {
  return v.reduce((a,b) => a+b, 0)/v.length;
}

function smoothOut (vector, variance) {
  var t_avg = avg(vector)*variance;
  var ret = Array(vector.length);
  for (var i = 0; i < vector.length; i++) {
    (function () {
      var prev = i>0 ? ret[i-1] : vector[i];
      var next = i<vector.length ? vector[i] : vector[i-1];
      ret[i] = avg([t_avg, avg([prev, vector[i], next])]);
    })();
  }
  return ret;
}

function display (x, y) {
  console.clear();
  console.assert(x.length === y.length);
  x.forEach((el, i) => console.log(`${el}\t\t${y[i]}`));
}

display(array, smoothOut(array, 0.85));

注意:它使用了一些 ES6 特性,例如粗箭头函数和模板字符串。 Firefox 35+ 和 Chrome 45+ 应该可以正常工作。否则请使用 babel repl。

我的方法基本上是预先计算数组中所有元素的平均值,并将其用作主要因素来计算新值以及当前元素值,即它之前的值,以及它之后的那个。我还将先前的值用作 计算的值,而不是原始数组中的值。随意根据您的需要进行实验和修改。您还可以传入“方差”参数来控制元素之间的差异。降低它会使元素彼此更接近,因为它会降低平均值。

放松平滑的轻微变化如下:

"use strict";
var array = [10, 13, 7, 11, 12, 9, 6, 5];

function avg (v) {
  return v.reduce((a,b) => a+b, 0)/v.length;
}

function smoothOut (vector, variance) {
  var t_avg = avg(vector)*variance;
  var ret = Array(vector.length);
  for (var i = 0; i < vector.length; i++) {
    (function () {
      var prev = i>0 ? ret[i-1] : vector[i];
      var next = i<vector.length ? vector[i] : vector[i-1];
      ret[i] = avg([t_avg, prev, vector[i], next]);
    })();
  }
  return ret;
}

function display (x, y) {
  console.clear();
  console.assert(x.length === y.length);
  x.forEach((el, i) => console.log(`${el}\t\t${y[i]}`));
}

display(array, smoothOut(array, 0.85));

不以平均值为主要因素。

随意尝试,希望对您有所帮助!

【讨论】:

    【解决方案2】:

    您描述的技术听起来像是Gaussian blur 的一维版本。将一维高斯数组的值乘以数组中的给定窗口,然后将结果相加。例如

    1. 假设一个高斯数组 {.242, .399, .242}
    2. 要计算输入数组的位置 n 处的新值 - 将输入数组的 n-1、n 和 n+1 处的值乘以 (1) 中的值,然后将结果相加。例如对于 [3, 5, 0, 8, 4, 2, 6], n = 1:

      n1 = 0.242 * 3 + 0.399 * 5 + 0.242 * 0 = 2.721

    您可以更改高斯方差以增加或减少模糊的影响。

    【讨论】:

    • 这与我正在寻找的非常接近。你是怎么想出高斯数组 [.242, .399, .242] 的?
    • 它们是高斯​​函数的离散值,(mean 0, sd = 1) at -1, 0, and 1.
    • 抱歉,您能否更具体地说明如何计算这些值?我假设你使用了this function。我了解平均值和标准差的去向;对于 x,您是否插入了 -1、0 和 1?
    • 我知道这是旧的,但我认为您可以在此处查找值:keisan.casio.com/exec/system/1180573188
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-26
    • 2015-08-09
    • 1970-01-01
    • 2013-10-08
    • 1970-01-01
    • 2017-05-16
    • 2018-07-16
    相关资源
    最近更新 更多