2016-04-22 1 views
4

J'ai des séries temporelles, et j'applique une fonction définie par l'utilisateur à chaque élément W dans les séries chronologiques.Matrice avec éléments de fenêtre coulissante

En ce moment j'utilise juste pour la boucle, glissez la fenêtre de la taille W et appliquez ma fonction aux éléments dans une fenêtre à chaque itération.

J'utilise Matlab et c'est très inefficace avec un "for loops" donc j'aimerais vectoriser cette opération. En tant que solution, je vois transformer un signal de longueur N en une matrice de taille (N - 1, W) où chaque rangée est une série temporelle dans différentes fenêtres et appliquant une fonction à cette matrice.

Alors, mes questions sont les suivantes:

  1. Comment transformer ma série de temps initial à une telle matrice? Disons que je suis en train de glisser la fenêtre avec l'étape X. Ainsi, la matrice (N - 1, W) n'apparaîtra pas, mais ((N - 1)/X, W). (Chaque ligne Xème de la matrice dans [1])

Exemple:

Disons que ma série de temps est:

T = [1, 5, 6, 8, 10, 14, 22] 
W = 3 
X = 1 

=> J'aimerais obtenir

[[1, 5, 6], 
[5, 6, 8], 
[6, 8, 10], 
[8, 10, 14], 
[10, 14, 22]] 

Si

W = 3 
X = 2 

=> J'aimerais obtenir

[[1, 5, 6], 
[6, 8, 10], 
[10, 14, 22]] 
+0

Vous devez avoir des informations plus avant avant vectorisation. Néanmoins, je ne vois pas un moyen de faire sans une boucle for ... – 16per9

+1

De quel type d'opération avez-vous besoin pour calculer? Est-ce qu'une convolution ne t'aide pas? –

+0

Ne pas rejeter les boucles si rapidement; Parfois, ils sont plus rapides que les alternatives. Mais je suis d'accord avec les commentaires précédents, nous avons besoin de plus d'informations sur les opérations que vous devez effectuer sur ces fenêtres. – beaker

Répondre

6

Création des indices droite avec bsxfun devrait certainement aider:

ind = bsxfun(@plus, 1:W, (0:X:numel(T)-W).'); 
out = T(ind); 

Création des indices de droite est la première étape, délimitée par la première ligne de code . Ce que fait ce code, c'est qu'il crée une matrice 2D où chaque ligne est les éléments à accéder par fenêtre d'intérêt. Si vous voulez acquérir de l'intuition sur la façon dont le code génère les indices, regardez spécifiquement le premier cas où X = 1; et W = 3;.

On peut voir que la première ligne consiste à accéder aux éléments 1, 2, 3. La deuxième ligne consiste à accéder aux éléments 2, 3, 4 ... jusqu'à la dernière rangée, qui est 5, 6, 7. Nous pouvons voir que nous devons accéder aux éléments voisins dans une fenêtre, et donc les indices de base doivent aller de 1, 2, 3, ou en général de 1 à W. Nous avons maintenant besoin de offset ces indices afin qu'ils soient centrés sur les bons éléments dans T par fenêtre. Le décalage pour la première fenêtre est simplement 0, le décalage suivant pour la deuxième fenêtre est simplement 1 jusqu'à la dernière rangée qui est 3. Nous voyons que pour chaque rangée, nous ajoutons 1 plus aux index de base que les rangées augmentent. Par conséquent, nous ajoutons 1 à chaque index de base pour la deuxième rangée, puis 2 pour chaque index de base dans la troisième rangée et ainsi de suite. Si vous ajoutez les indices de base avec les indices de décalage, vous obtenez ainsi les indices corrects pour accéder aux bons éléments dans T.

De même si X = 2; et W = 3;, nous voyons que nous avons encore des indices de base de 1, 2, 3.Cependant, les bons éléments pour accéder maintenant sont 1, 2, 3 pour la première rangée, puis 3, 4, 5 pour la deuxième rangée puis 5, 6, 7 pour la troisième rangée. Pour chaque ligne, nous compensons maintenant les indices de base par au lieu de 1 maintenant. Par conséquent, la deuxième rangée ajoute 2 à chaque index de base, puis nous ajoutons 4 à chaque index de base pour la troisième rangée et ainsi de suite.

En général, les indices de base sont créés en utilisant un vecteur 1:W et les indices de décalage sont créés en utilisant un vecteur 0:X:numel(T)-W. La soustraction de W est nécessaire afin que nous ne sortons pas des limites lors de l'échantillonnage du signal selon les exigences. Pour créer ces indices dont nous venons de parler, bsxfun gère cela pour nous.

Nous créons un vecteur ligne de 1:W qui correspond aux index de base et un vecteur colonne de (0:X:numel(T)-W).' qui correspond aux décalages par fenêtre. Notez que le premier décalage commence à 0, puis nous augmentons de X le montant pour nous assurer que le centre correct est calculé pour placer nos indices de base à. Nous nous arrêtons jusqu'à ce que nous atteignions numel(T)-W éléments, ce qui est la condition que vous avez indiquée. En utilisant bsxfun, deux matrices 2D temporaires sont créées où le vecteur de ligne est dupliqué pour autant de lignes qu'il y a de lignes dans le vecteur de colonne et le vecteur de colonne est dupliqué pour autant de colonnes qu'il y a dans le vecteur ligne. Une fois que vous avez ajouté ces deux matrices, vous obtenez la matrice d'index résultante.

L'exécution du code avec W = 3; et X = 1; donne:

>> T = [1, 5, 6, 8, 10, 14, 22]; 
>> X = 1; 
>> W = 3; 
>> ind = bsxfun(@plus, 1:W, (0:X:numel(T)-W).') 

ind = 

    1  2  3 
    2  3  4 
    3  4  5 
    4  5  6 
    5  6  7 

De même, si W = 3; et X = 2; nous obtenons aussi:

>> T = [1, 5, 6, 8, 10, 14, 22]; 
>> X = 2; 
>> W = 3; 
>> ind = bsxfun(@plus, 1:W, (0:X:numel(T)-W).') 

ind = 

    1  2  3 
    3  4  5 
    5  6  7 

Vous pouvez vérifier par vous-même que ces indices correspondent aux éléments corrects dans T pour créer votre matrice souhaitée dans ce cas.

Nous utilisons enfin ce pour indexer dans notre matrice pour saisir les bons éléments:

out = T(ind); 

Faire cela pour X = 1; et W = 3; donne:

>> out = T(ind) 

out = 

    1  5  6 
    5  6  8 
    6  8 10 
    8 10 14 
    10 14 22 

De même pour X = 2; et W = 3; donne:

>> out = T(ind) 

out = 

    1  5  6 
    6  8 10 
    10 14 22 
0

Basé sur la réponse de Rayryeng j'ai écrit une fonction qui fait exactement cela, plus quelques fonctionnalités supplémentaires. Il est conçu pour générer des indices d'autorégression sur une série temporelle univariée. Il peut facilement être utilisé pour le cas multivarié en utilisant simplement les mêmes indices et en concaténant les données référencées.

Il renvoie les indices à la variable prédictive X (selon votre demande) et pour les régresseurs y ainsi. En outre, vous avez la possibilité d'appliquer un «masque» aux variables de prédicteur X tout en faisant glisser la fenêtre.Par exemple, avec une fenêtre de 21 étapes, vous pouvez choisir [T-2 T-3 T-5 T-8, T-13 T-21] pour X et T pour y

Vous pouvez également modifier l'horizon de prédiction - combien d'étapes dans le futur les indices pour et sont. Par exemple X = [T-1 T-2] et y = T + 2

Espérons que quelqu'un d'autre vous le trouverez utile.

% get_Sliding_Indexes: 
%  Useful for autoregression on a univariate time series. 
%  Returns the indexes for the predictor and response variables 
%  according to a sliding window. 
% 
% Copyright (C) 20016 Florin Schimbinschi 
% 
% Parameters: 
%  numRecords - the number of records in the dataset 
% 
%  windowLag - number of past samples to take - it will be equal to 
%   the size of the predictor vector X. Default 10 
% 
%  predHorizon - the prediction horizon is the number of steps into 
%   the future that predictions are to be made. Default 1 
% 
%  windowPattern - by default the window will take all consecutive 
%   values in the past over the window lag size, however it is 
%   possible to sample using a custom pattern. 
%   For example taking every second value can be done by setting 
%   this parameter to 1:2:5. Default 1:windowLag 
% 
%  stepSize - number of steps taken when window is moved. Default 1 
% 
% Returns: 
%  indX - predictor variable indexes 
%  indY - response variable indexes 
% 
% 
%  windowPattern = 1:2:9 __ structure between [] is moved to 
%   / \  / the right by stepSize units 
% >------[(9-7-5-3-1)---(y)]---------------> 
%   \_______/ \_/ 
%   X = [13579] predHorizon = 3 
% 
% 
% Example on a multivariate time series (two) with 6 records: 
% 
%  data2d = [ .1 .2 .3 .4 .5 .6 
%    .11 .22 .33 .44 .55 .66]'; 
% 
%  [X, y] = getSlidingIndexes(size(data2d,1), 4) 
%  X = 
%   1  2  3  4 
%   2  3  4  5 
%  y = 
%   5 
%   6 
% 
%  Assuming we are interested in the second series (column): 
% 
%  series2 = data2d(:,2); 
% 
%  series2(X) 
%  ans = 
%   0.1100 0.2200 0.3300 0.4400 
%   0.2100 0.3300 0.4400 0.5500 
% 
%  series2(y) 
%  ans = 
%   0.5500 
%   0.6600 
% 
function [indX, indY] = get_Sliding_Indexes(numRecords, ... 
         windowLag, predHorizon, windowPattern, stepSize) 

    if ~exist('numRecords','var') || isempty(numRecords) 
     error('The number of records in the dataset is not specified'); 
    end 
    if ~exist('stepSize','var') || isempty(stepSize) 
     stepSize = 1; % steps taken when moving the window 
    end 
    if ~exist('predHorizon','var') || isempty(predHorizon) 
     predHorizon = 1; % aiming to predict this many steps in the future 
    end 
    if ~exist('windowLag','var') || isempty(windowLag) 
     windowLag = 10; % number of time steps to look back 
    end 
    if exist('windowLag','var') && (windowLag > numRecords) 
     error('The size of the window is larger than the number of observations'); 
    end 
    if ~exist('windowPattern','var') || isempty(windowPattern) 
     windowPattern = 1:windowLag; % pattern of sampling data 
    end 
    if exist('windowPattern','var') && windowPattern(end) > windowLag 
     error('The window pattern must stop at the window lag specified'); 
    end 

    % the number of samples in the window 
    maxSample = max(windowPattern); 

    indX = bsxfun(@plus, windowPattern, ... 
     (0:stepSize:(numRecords - maxSample - predHorizon))'); 
    indY = bsxfun(@plus, max(windowPattern) + predHorizon, ... 
     (0:stepSize:(numRecords - maxSample - predHorizon))'); 
end 

Vous pouvez également trouver le code ici: https://au.mathworks.com/matlabcentral/fileexchange/58730-get-sliding-indexes-numrecords--windowlag--predhorizon--windowpattern--stepsize-