2016-02-04 4 views
0

Je voudrais d'abord décrire mon problème: Ce que je veux faire est de calculer le nombre de pics sur les prix dans une fenêtre de 24 heures, alors que je possède des données demi-heure.Erreur dans rollapply: indice en dehors des limites

J'ai vu tous les posts de Stackoverflow comme e.g. celui-ci: Rollapply for time series

(S'il y a les plus pertinents, s'il vous plaît laissez-moi savoir;))

Comme je ne peux pas et devrait probablement pas télécharger mes données, voici un exemple minimal: je simule un échantillon aléatoire variable, le convertit en un objet xts, et utilise une fonction définie par l'utilisateur pour détecter les "pointes" (bien sûr assez ridicule dans ce cas, mais illustre l'erreur).

library(xts) 
##########Simulate y as a random variable 
y <- rnorm(n=100) 
##########Add a date variable so i can convert it to a xts object later on 
yDate <- as.Date(1:100) 
##########bind both variables together and convert to a xts object 
z <- cbind(yDate,y) 
z <- xts(x=z, order.by=yDate) 
##########use the rollapply function on the xts object: 
x <- rollapply(z, width=10, FUN=mean) 

La fonction fonctionne comme elle le devrait: elle prend les 10 valeurs précédentes et calcule la moyenne. Puis, j'ai défini une fonction propre pour trouver des pics: Un pic est un maximum local (supérieur à m points autour de lui) ET est au moins aussi grand que la moyenne des séries temporelles + h. Cela conduit à:

find_peaks <- function (x, m,h){ 
    shape <- diff(sign(diff(x, na.pad = FALSE))) 
    pks <- sapply(which(shape < 0), FUN = function(i){ 
    z <- i - m + 1 
    z <- ifelse(z > 0, z, 1) 
    w <- i + m + 1 
    w <- ifelse(w < length(x), w, length(x)) 
    if(all(x[c(z : i, (i + 2) : w)] <= x[i + 1])&x[i+1]>mean(x)+h) return(i + 1) else return(numeric(0)) 
    }) 
    pks <- unlist(pks) 
    pks 
} 

Et fonctionne très bien: Retour à l'exemple:

plot(yDate,y) 
#Is supposed to find the points which are higher than 3 points around them 
#and higher than the average: 
#Does so, so works. 
points(yDate[find_peaks(y,3,0)],y[find_peaks(y,3,0)],col="red") 

Cependant, en utilisant la fonction rollapply() conduit à:

x <- rollapply(z,width = 10,FUN=function(x) find_peaks(x,3,0)) 
#Error in `[.xts`(x, c(z:i, (i + 2):w)) : subscript out of bounds 

j'ai pensé, eh bien, peut-être que l'erreur se produit car elle peut s'exécuter dans un index négatif pour les premiers points, à cause du paramètre m. Malheureusement, mettre m à zéro ne change pas l'erreur.

J'ai essayé de tracer cette erreur aussi, mais je ne trouve pas la source. Quelqu'un peut-il m'aider ici?

Edit: Une image de pointes: Spikes on the australian Electricity Market. find_peaks(20,50) determines the red points to be spikes, find_peaks(0,50) additionally finds the blue ones to be spikes (therefore, the second parameter h is important, because the blue points are clearly not what we want to analyse when we talk about spikes).

+1

Je suis confus quant à ce que le but est ici. Est-ce que vous essayez de trouver des pics basés sur la moyenne globale et ensuite en utilisant cela avec les quelques points autour d'une valeur donnée? Vos erreurs de code à votre déclaration 'if'. Dans votre objet 'xts' vous avez deux colonnes, donc les indices calculés' c (z: i, (i + 2): w) 'sont'> 100'. L'opérateur de sous-ensemble '[.xts' essaie de prendre des lignes basées sur l'index et il y a' <100' lignes. – jamieRowen

+0

Il semblerait aussi que les opérateurs de relation ne font pas comme vous pouvez attendre ici avec un objet 'xts' – jamieRowen

+0

Je suis désolé, je vais essayer de m'exprimer d'une meilleure manière: La fonction de crête est censée trouver des pics. Les pics sont définis comme des points plus grands que des m points dans leur environnement, et (parce que dans les périodes à faible volatilité ces points peuvent être très bas) doivent dépasser un seuil. L'objectif global est de déterminer le nombre de pics dans une fenêtre de 24 heures ou un jour donné, ce qui devrait être donné par la longueur (find_peaks). – user18093

Répondre

0

Je ne suis toujours pas tout à fait sûr de ce qu'il est que vous êtes après. En supposant que donné une fenêtre de données que vous voulez identifier si son centre est plus grand que le reste de la fenêtre en même temps comme étant supérieure à la moyenne de la fenêtre + h alors vous pourriez faire ce qui suit:

peakfinder = function(x,h = 0){ 
    xdat = as.numeric(x) 
    meandat = mean(xdat) 
    center = xdat[ceiling(length(xdat)/2)] 
    ifelse(all(center >= xdat) & center >= (meandat + h),center,NA) 
} 

y <- rnorm(n=100) 
z = xts(y, order.by = as.Date(1:100)) 
plot(z) 
points(rollapply(z,width = 7, FUN = peakfinder, align = "center"), col = "red", pch = 19) 

Bien qu'il me semble que si le point central est plus grand que ses voisins, il est nécessairement plus grand que la moyenne locale aussi cette partie de la fonction ne serait pas nécessaire si h >= 0. Si vous voulez utiliser la moyenne globale de la série temporelle, remplacez simplement le calcul de meandat par la moyenne globale pré-calculée passée en argument à peakfinder.

+0

J'apprécie grandement vos efforts, je pense que je me suis exprimé très mal. Je ne cherche pas à savoir si la médiane est supérieure à la moyenne. L'objectif global est de déterminer le nombre de pointes dans un intervalle donné. Cela peut être fait de la manière que vous pourriez suggérer, je pensais que j'utiliserais simplement la fonction find_spikes que j'ai écrite, puis j'utiliserais length (find_spikes) pour déterminer le nombre de spikes. J'ai inclus une image de "pointes" dans mon ancien post. – user18093

+0

Résout-il votre problème? Si oui, acceptez-vous la réponse, sinon laissez-moi savoir quel est le problème et je vais essayer de le réparer. – jamieRowen

+0

Tout d'abord, merci beaucoup. Cependant, comme je suis relativement nouveau dans les langages de programmation, j'ai du mal à comprendre ce que fait votre code. Il semble déterminer le "centre" (médiane des dates si vous voulez) et le marquer comme un pic si ses valeurs sont plus grandes que celles de toutes les autres valeurs de l'intervalle, et plus grandes que la moyenne + h. Après cette logique, il ne pourrait y avoir qu'un seul pic par intervalle. Avez-vous une idée sur la façon de modifier votre approche afin qu'il puisse y avoir autant de pics par intervalle que souhaité (c'est-à-dire même infiniment nombreux) – user18093