2014-10-22 23 views
5

Jestem dość obeznany z R, jak używam go od kilku lat. Niestety, nie jestem zbyt dobrze zorientowany w tworzeniu funkcji, które wymagają zapętlenia lub powtórzenia równania. Problem wygląda następująco:Powtarzanie lub pętla argumentu

Mam wektor zawierający ponad 1000 wartości. Chciałbym obliczyć absolutną różnicę między dwoma zestawieniowymi środkami o jednakowej wielkości z podzbioru tego wektora.

Oto przykład.

mam wektor (VEC) o długości 8

[1] 0.12472963 1.15341289 -1.09662288 -0.73241639 0.06437658 -0.13647136 -1.52592048 1.46450084 

ja jak obliczyć średnią z pierwszych wartości 2 (0.12472963, 1.15341289) oraz uzyskanie bezwzględnej różnicy ze średnią z następujących wartości 2 (-1.09662288 -0.73241639), a następnie, idąc dalej w dół wektora.

W tym przypadku, mogę z łatwością korzystać z następującego równania:

abs(mean(vec[1:2])-mean(vec[3:4])) 

i stopniowo zwiększać każdą liczbę o 1, tak aby pracować moją drogę w dół ręcznie do końca wektora. Otrzymałbym następujący wektor.

[1] 1.553591 0.3624149 0.8784722 0.497176 0.005337574 

Chciałbym jednak mieć zautomatyzowaną procedurę, która pozwala mi być to zrobić na długich wektorów i zmienić liczbę wartości, z którego można obliczyć środki.

Wydaje mi się, że powinna być względnie prosta, ale nie wiem od czego zacząć.

+1

Możecie zajrzeć do 'rollapply()' 'z pakietu zoo'. –

Odpowiedz

7

Zastosowanie filter.

c(abs(filter(vec, c(0.5, 0.5, -0.5, -0.5), sides=1)[-(1:3)])) 
#[1] 1.55359090 0.36241491 0.87847224 0.49717601 0.00533757 
+0

Wydaje się być najszybszym przesłanym do tej pory. –

2

Stosując rollapply z zoo

library(zoo) 
n <- 2 
n1 <- length(vec) 

abs(rollapply(vec[1:(n1-n)], 2, mean)-rollapply(vec[(n+1):n1], 2,mean)) 
#[1] 1.55359090 0.36241491 0.87847224 0.49717601 0.00533757 

Również inne odmiany powyższego kodu są (z skomentowane przez @G Grothendieck- jednego z twórców zoo pakietu)

abs(rollmean(vec[1:(n1-n)], 2) - rollmean(vec[(n+1):n1], 2)) #using 
    #`rollmean` instead of `rollapply` 

lub

rollapply(vec, 4, function(x) abs(mean(x[1:2]) - mean(x[3:4]))) 

lub

abs(rollapply(vec, 4, "%*%", c(1, 1, -1, -1)/2)) 
+1

Te odmiany również działają: 'abs (rollmean (vec [1: (n1-n)], 2) - rollmean (vec [(n + 1): n1], 2))' i 'rollapply (vec, 4, funkcja (x) abs (średnia (x [1: 2]) - średnia (x [3: 4]))) 'i' abs (rollapply (vec, 4, "% *%", c (1, 1, -1, -1)/2)) '. –

+0

@G. Grothendieck Dzięki za komentarz i przedstawienie zmian. – akrun

1

Jak zawsze, dostroić się z:

vec<-rep(c( 0.12472963 , 1.15341289, -1.09662288, -0.73241639 , 0.06437658, -0.13647136 ,-1.52592048 , 1.46450084 ),100) 

microbenchmark(roland(vec),akrun(vec),times=3) 

Unit: microseconds 
     expr  min   lq  mean median  uq  max 
    roland(vec) 564.128 565.2275 647.3353 566.327 688.939 811.551 
    akrun(vec) 3717.410 3982.1535 4218.3057 4246.897 4468.753 4690.610 
neval 
    3 
    3 
+1

Zaktualizowałem swoją odpowiedź z niewielką zmianą, która powinna poprawić wydajność i zapewnia poprawną obsługę wartości "NA". – Roland

+0

@RichardScriven awwwwww .... :-) –