平滑数组的值
Smoothing out values of an array
如果我有一个数字数组,例如 [3, 5, 0, 8, 4, 2, 6],有没有办法“平滑”这些值,使它们彼此更接近并且显示更少的方差?
我已经研究过使用称为高斯函数的东西对 1 维情况 进行数据窗口化,这是我的数组,但在实现它时遇到了问题。 This thread 似乎正好解决了我需要的问题,但我不明白用户 naschilling(第二个 post)是如何得出高斯矩阵值的。
上下文: 我正在研究一个音乐波形发生器(借鉴了 SoundCloud 的设计),它映射了歌曲在时间 t[=49 的振幅=] 到相应的条形高度。不幸的是,有很多噪音,当程序映射一个微小的幅度导致高度突然下降时,它看起来特别难看。我基本上想平滑条形高度,这样它们就不会那么多变了。
我使用的语言是Javascript。
编辑:抱歉,让我更具体地说明一下 "smoothing out" 值。根据上面链接的线程,用户拿了一个数组
[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);
有趣的问题!
平滑值的算法显然可以变化 很多,但这是我的看法:
"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。
我的方法基本上是预先计算数组中所有元素的平均值,并将其用作主要因子来计算新值和当前元素值,它之前的一个,它之后的一个。我还使用先验值作为 newly 计算的值,而不是原始数组中的值。随意根据您的需要进行试验和修改。也可以传入一个"variance"参数来控制元素之间的差异。降低它会使元素彼此更接近,因为它会降低平均值。
放松平滑的轻微变化是这样的:
"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));
不以平均值为主要因素
随时尝试,希望对您有所帮助!
您描述的技术听起来像是 Gaussian blur 的一维版本。将一维高斯数组的值乘以数组中给定的 window 并对结果求和。例如
- 假设一个高斯数组 {.242, .399, .242}
要计算输入数组位置 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
您可以改变高斯方差来增加或减少模糊的影响。
如果我有一个数字数组,例如 [3, 5, 0, 8, 4, 2, 6],有没有办法“平滑”这些值,使它们彼此更接近并且显示更少的方差?
我已经研究过使用称为高斯函数的东西对 1 维情况 进行数据窗口化,这是我的数组,但在实现它时遇到了问题。 This thread 似乎正好解决了我需要的问题,但我不明白用户 naschilling(第二个 post)是如何得出高斯矩阵值的。
上下文: 我正在研究一个音乐波形发生器(借鉴了 SoundCloud 的设计),它映射了歌曲在时间 t[=49 的振幅=] 到相应的条形高度。不幸的是,有很多噪音,当程序映射一个微小的幅度导致高度突然下降时,它看起来特别难看。我基本上想平滑条形高度,这样它们就不会那么多变了。
我使用的语言是Javascript。
编辑:抱歉,让我更具体地说明一下 "smoothing out" 值。根据上面链接的线程,用户拿了一个数组
[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);
有趣的问题!
平滑值的算法显然可以变化 很多,但这是我的看法:
"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。
我的方法基本上是预先计算数组中所有元素的平均值,并将其用作主要因子来计算新值和当前元素值,它之前的一个,它之后的一个。我还使用先验值作为 newly 计算的值,而不是原始数组中的值。随意根据您的需要进行试验和修改。也可以传入一个"variance"参数来控制元素之间的差异。降低它会使元素彼此更接近,因为它会降低平均值。
放松平滑的轻微变化是这样的:
"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));
不以平均值为主要因素
随时尝试,希望对您有所帮助!
您描述的技术听起来像是 Gaussian blur 的一维版本。将一维高斯数组的值乘以数组中给定的 window 并对结果求和。例如
- 假设一个高斯数组 {.242, .399, .242}
要计算输入数组位置 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
您可以改变高斯方差来增加或减少模糊的影响。