所以我自己做了一些数学运算,因为我很好奇如何获得权重比(好像线性上采样到公倍数,然后只从大数组中提取目标值 - 但没有创建大数组,只是使用权重来知道多少左+右元素对特定值有贡献)。
示例代码确实总是通过简单的加权平均值创建新值(即 123.4 的 40% 和 60% 567.8 将给出“升级”值 390.04),没有随机用于对升级后的值进行填充(将那部分留给 OP)。
比率是这样的:
如果大小为M的向量被放大到大小N ( M <= N )(“upscale”将始终保留输入向量的第一个和最后一个元素,这些在本提案中是“固定的”)
那么每个放大的元素都可以被视为介于一些原始元素 [i, i+1] 之间的某个位置。
如果我们声明源元素 [i, i+1] 之间的“距离”等于d = N-1,那么放大后的元素之间的距离总是可以表示为一些j/d其中j :[0,d] (当j是实际的d时,它正好在 "i+1" 元素处,可以认为与j =0 相同的情况,但使用 [i+1,i+2] 源元素)
然后两个放大元素之间的距离为M-1。
因此,当源向量的大小为 4 且放大后的向量大小应为 5 时,放大后元素的比率为 [ [4/4,0/4], [1/4,3/4], [2/4,2/ 4], [3/4,1/4], [0/4,4/4] ] 元素(索引到向量) [ [0,1], [0,1], [1,2], [ 2, 3], [2, 3] ]。(源元素之间的“距离”是 5-1=4,那就是标准化权重的“/4”,放大元素之间的“距离”是 4-1=3,这就是为什么比率移动 [-3,+ 3] 在每一步)。
恐怕我的描述远非“显而易见”(弄清楚后在我脑海中的感觉),但如果您将其中的一些放入电子表格并玩弄它,希望它会有意义。或者,也许您可以调试代码以更好地感受上面的喃喃自语是如何转化为真实代码的。
代码示例 1,只有当权重完全完全覆盖源元素时,这个才会“复制”源元素(即在示例数据中,只有第一个和最后一个元素被“复制”,其余的放大元素是原始值的加权平均值)。
#include <iostream>
#include <vector>
#include <cassert>
static double get_upscale_value(const size_t total_weight, const size_t right_weight, const double left, const double right) {
// do the simple weighted average for demonstration purposes
const size_t left_weight = total_weight - right_weight;
return (left * left_weight + right * right_weight) / total_weight;
}
std::vector<double> upsample_weighted(std::vector<double>& in, size_t n)
{
assert( 2 <= in.size() && in.size() <= n ); // this is really only upscaling (can't downscale)
// resulting vector variable
std::vector<double> upscaled;
upscaled.reserve(n);
// upscaling factors variables and constants
size_t index_left = 0; // first "left" item is the in[0] element
size_t weight_right = 0; // and "right" has zero weight (i.e. in[0] is copied)
const size_t in_weight = n - 1; // total weight of single "in" element
const size_t weight_add = in.size() - 1; // shift of weight between "upscaled" elements
while (upscaled.size() < n) { // add N upscaled items
if (0 == weight_right) {
// full weight of left -> just copy it (never tainted by "upscaling")
upscaled.push_back(in[index_left]);
} else {
// the weight is somewhere between "left" and "right" items of "in" vector
// i.e. weight = 1..(in_weight-1) ("in_weight" is full "right" value, never happens)
double upscaled_val = get_upscale_value(in_weight, weight_right, in[index_left], in[index_left+1]);
upscaled.push_back(upscaled_val);
}
weight_right += weight_add;
if (in_weight <= weight_right) {
// the weight shifted so much that "right" is new "left"
++index_left;
weight_right -= in_weight;
}
}
return upscaled;
}
int main(int argc, const char *argv[])
{
std::vector<double> in { 10, 20, 30 };
// std::vector<double> in { 20, 10, 40 };
std::vector<double> upscaled = upsample_weighted(in, 14);
std::cout << "upsample_weighted from " << in.size() << " to " << upscaled.size() << ": ";
for (const auto i : upscaled) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
输出:
upsample_weighted 从 3 到 14:10 11.5385 13.0769 14.6154 16.1538 17.6923 19.2308 20.7692 22.3077 23.8462 25.3846 26.9231 28.4615 30
代码示例 2,这个将“复制”每个源元素并使用加权平均来填补之间的空白,因此尽可能多地保留原始数据(因为结果的价格不是原始数据集的线性放大,但“别名”为由目标大小定义的“网格”):
(代码几乎与第一个相同,除了if
升频器中的一行)
#include <iostream>
#include <vector>
#include <cassert>
static double get_upscale_value(const size_t total_weight, const size_t right_weight, const double left, const double right) {
// do the simple weighted average for demonstration purposes
const size_t left_weight = total_weight - right_weight;
return (left * left_weight + right * right_weight) / total_weight;
}
// identical to "upsample_weighted", except all source values from "in" are copied into result
// and only extra added values (to make the target size) are generated by "get_upscale_value"
std::vector<double> upsample_copy_preferred(std::vector<double>& in, size_t n)
{
assert( 2 <= in.size() && in.size() <= n ); // this is really only upscaling (can't downscale)
// resulting vector variable
std::vector<double> upscaled;
upscaled.reserve(n);
// upscaling factors variables and constants
size_t index_left = 0; // first "left" item is the in[0] element
size_t weight_right = 0; // and "right" has zero weight (i.e. in[0] is copied)
const size_t in_weight = n - 1; // total weight of single "in" element
const size_t weight_add = in.size() - 1; // shift of weight between "upscaled" elements
while (upscaled.size() < n) { // add N upscaled items
/* ! */ if (weight_right < weight_add) { /* ! this line is modified */
// most of the weight on left -> copy it (don't taint it by upscaling)
upscaled.push_back(in[index_left]);
} else {
// the weight is somewhere between "left" and "right" items of "in" vector
// i.e. weight = 1..(in_weight-1) ("in_weight" is full "right" value, never happens)
double upscaled_val = get_upscale_value(in_weight, weight_right, in[index_left], in[index_left+1]);
upscaled.push_back(upscaled_val);
}
weight_right += weight_add;
if (in_weight <= weight_right) {
// the weight shifted so much that "right" is new "left"
++index_left;
weight_right -= in_weight;
}
}
return upscaled;
}
int main(int argc, const char *argv[])
{
std::vector<double> in { 10, 20, 30 };
// std::vector<double> in { 20, 10, 40 };
std::vector<double> upscaled = upsample_copy_preferred(in, 14);
std::cout << "upsample_copy_preferred from " << in.size() << " to " << upscaled.size() << ": ";
for (const auto i : upscaled) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
输出:
upsample_copy_preferred 从 3 到 14:10 11.5385 13.0769 14.6154 16.1538 17.6923 19.2308 20 22.3077 23.8462 25.3846 26.9231 28.4615 30
(请注意,示例 1 中的“20.7692”在这里只是“20” - 原始样本的副本,即使此时如果考虑线性插值,“30”的权重也很小)