Как сделать взвешенное усреднение n последовательных значений в массиве

У меня есть вектор значений 900×1 (в MATLAB). Каждые 9 последовательных значений должны быть усреднены - без наложения - в результате получается вектор значений 100×1. Проблема в том, что усреднение должно быть взвешено на основе вектора взвешивания [1 2 1;2 4 2;1 2 1], Есть ли эффективный способ усреднения? Я слышал о функции конвектора в MATLAB; Это полезно?

1 ответ

conv работает путем скольжения ядра через ваши данные. Но в вашем случае, вам нужна маска для перемещения по вашим данным, так что я не думаю, conv будет работать на вас.

Если вы хотите использовать существующую функцию MATLAB, вы можете сделать это (я должен предположить, что ваша весовая матрица имеет только одно измерение):

kernel = [1;2;1;2;4;2;1;2;1];
in_matrix = reshape(in_matrix, 9, 100);
base = sum(kernel);
out_matrix = bsxfun(@times, in_matrix, kernel);
result = sum(out_matrix,1)/base;

Я не знаю, есть ли какой-нибудь умный способ ускорить это. bsxfun допускает одноэлементное расширение, но, возможно, не уменьшение размера.

Более быстрый способ - использовать мекс. Откройте новый файл в редакторе, вставьте следующий код и сохраните файл как weighted_average.c,

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    double *in_matrix, *kernel, *out_matrix, base;              
    int niter;
    size_t nrows_data, nrows_kernel;                   

    /* Get number of element along first dimension of input matrix. */
    nrows_kernel = mxGetM(prhs[1]);    
    nrows_data = mxGetM(prhs[0]);

    /* Create output matrix*/
    plhs[0] = mxCreateDoubleMatrix((mwSize)nrows_data/nrows_kernel,1,mxREAL);

    /* Get a pointer to the real data */
    in_matrix = mxGetPr(prhs[0]);
    kernel = mxGetPr(prhs[1]);
    out_matrix = mxGetPr(plhs[0]);

    /* Sum the elements in weighting array */
    base = 0;
    for (int i = 0; i < nrows_kernel; i +=1)
    {
        base += kernel[i];
    }

    /* Perform calculation */
    niter = nrows_data/nrows_kernel;
    for (int i = 0; i < niter ; i += 1)
    {   
        for (int j = 0; j < nrows_kernel; j += 1)
        {
            out_matrix[i] += in_matrix[i*nrows_kernel+j]*kernel[j];
        }
        out_matrix[i] /= base;
    }    
}

Затем в командной строке введите

mex weighted_average.c

Чтобы использовать это:

result = weighted_average(input, kernel);

Обратите внимание, что оба input а также kernel должна быть матрица M x 1. На моем компьютере первый метод занял 0,0012 секунды. Второй метод занял 0,00007 секунды. Это на порядок быстрее, чем первый метод.

Другие вопросы по тегам