Можно ли извлечь точки данных из данных скользящего среднего?
Другими словами, если набор данных имеет только простые скользящие средние из предыдущих 30 точек, возможно ли извлечь исходные точки данных?
Если так, то как?
Можно ли извлечь точки данных из данных скользящего среднего?
Другими словами, если набор данных имеет только простые скользящие средние из предыдущих 30 точек, возможно ли извлечь исходные точки данных?
Если так, то как?
Ответы:
+1 к ответу Фаби, который завершен. Просто примечание, чтобы перевести его на R, основываясь на пакетах, которые я нашел для выполнения операций под рукой. В моем случае у меня были данные, которые представляют собой прогнозы температуры NOAA на трехмесячной основе: январь-февраль-март, февраль-март-апрель, март-апрель-май и т. Д., И я хотел разбить их на (приблизительные) месячные значения, предполагая, что температура каждого трехмесячного периода по существу является средней.
library (Matrix)
library (matrixcalc)
# Feb-Mar-Apr through Nov-Dec-Jan temperature forecasts:
qtemps <- c(46.0, 56.4, 65.8, 73.4, 77.4, 76.2, 69.5, 60.1, 49.5, 41.2)
# Thus I need a 10x12 matrix, which is a band matrix but with the first
# and last rows removed so that each row contains 3 1's, for three months.
# Yeah, the as.matrix and all is a bit obfuscated, but the results of
# band are not what svd.inverse wants.
a <- as.matrix (band (matrix (1, nrow=12, ncol=12), -1, 1)[-c(1, 12),])
ai <- svd.inverse (a)
mtemps <- t(qtemps) %*% t(ai) * 3
Который прекрасно работает для меня. Спасибо @fabee.
РЕДАКТИРОВАТЬ: ОК, обратно переводя мой R на Python, я получаю:
from numpy import *
from numpy.linalg import *
qtemps = transpose ([[46.0, 56.4, 65.8, 73.4, 77.4, 76.2, 69.5, 60.1, 49.5, 41.2]])
a = tril (ones ((12, 12)), 2) - tril (ones ((12, 12)), -1)
a = a[0:10,:]
ai = pinv (a)
mtemps = dot (ai, qtemps) * 3
(Для отладки которого потребовалось намного больше времени, чем для версии R. Во-первых, я не так хорошо знаком с Python, как с R, но также потому, что R гораздо удобнее использовать в интерактивном режиме.)
Я пытаюсь выразить сказанное в ответе. Допустим, у вас есть большой вектор с n = 2000 записей. Если вы вычисляете скользящее среднее с окном длины ℓ = 30 , вы можете записать это как умножение векторной матрицы y = A x вектора x с матрицей
которая имеет из них , которые сдвинуты по мере продвижения по рядам , пока 30 из них не попал в конец матрицы. Здесь усредненный вектор у имеет размеры 1970 года. Матрица имеет 1970 строк и 2000 столбцов. Следовательно, оно не обратимо.
Если вы не знакомы с матрицами, думать об этом как системы линейных уравнений: вы ищете для переменных таким образом, что в среднем в течение первых тридцати выходов у 1 , среднего по второй урожайности тридцать у 2 и так далее.
Проблема с системой уравнений (и матрицей) состоит в том, что в ней больше неизвестных, чем уравнений. Таким образом, вы не можете однозначно определить ваши неизвестных . Интуитивно понятная причина в том, что вы теряете измерения при усреднении, потому что первые тридцать измерений x не получают соответствующий элемент по y, поскольку вы не можете сместить окно усреднения за пределы x .
Один из способов сделать или, что то же самое, систему уравнений, разрешимым - это создать еще 30 уравнений (или еще 30 строк для A ), которые предоставляют дополнительную информацию (линейно независимы от всех других строк A ).
Другой, может быть проще, способ заключается в использовании Псевдообратного от A . Это порождает вектор z = A † y, который имеет ту же размерность, что и x, и обладает свойством минимизации квадратичного расстояния между y и A z (см. Википедию ).
Кажется, это работает довольно хорошо. Вот пример, где я нарисовал примеров из гауссовского распределения, добавил пять, усреднил их и восстановил x по псевдообратному.
Многие числовые программы предлагают псевдообращения (например, Matlab, Numpy в Python и т. Д.).
Вот код Python для генерации сигналов из моего примера:
from numpy import *
from numpy.linalg import *
from matplotlib.pyplot import *
# get A and its inverse
A = (tril(ones((2000,2000)),-1) - tril(ones((2000,2000)),-31))/30.
A = A[30:,:]
pA = pinv(A) #pseudo inverse
# get x
x = random.randn(2000) + 5
y = dot(A,x)
# reconstruct
x2 = dot(pA,y)
plot(x,label='original x')
plot(y,label='averaged x')
plot(x2,label='reconstructed x')
legend()
show()
Надеюсь, это поможет.