Есть ли более быстрый способ получить процентное изменение? - PullRequest
1 голос
/ 23 октября 2011

У меня есть фрейм данных с около 25000 записей и 10 столбцов. Я использую код для определения изменения предыдущего значения в том же столбце (NewVal) на основе другого столбца (y), в котором уже есть процентное изменение.

x=c(1:25000)
y=rpois(25000,2)
z=data.frame(x,y)
z[1,'NewVal']=z[1,'x']

Итак, я запустил это:

for(i in 2:nrow(z)){z$NewVal[i]=z$NewVal[i-1]+(z$NewVal[i-1]*(z$y[i]/100))}

Это займет гораздо больше времени, чем я ожидал. Конечно, я могу быть нетерпеливым человеком, как однажды сказал мне ужасное письмо, составленное для меня, но я пытаюсь вырваться из мира Excel (после того, как я прочитал http://www.burns -stat.com / pages / Tutor / spreadsheet_addiction.html , что вызывает у меня больше проблем, поскольку я начал не доверять данным - в этом письме также упоминались мои проблемы с доверием).

Я хотел бы сделать это без использования каких-либо функций из пакетов, поскольку я хотел бы знать, какова формула для создания значений - или, если хотите, я являюсь требовательным управляющим в соответствии с этим дружественным посланием.

Я также хотел бы знать, как получить скользящее среднее, как RollMan в CaTools. Или это, или как мне понять, какова их формула? Я попытался ввести rollmean, и я думаю, что это относится к другой функции (я новичок в R). Вероятно, это должен быть другой вопрос, но, как сказано в этом письме, я никогда не принимаю правильных решений в своей жизни.

Ответы [ 2 ]

7 голосов
/ 23 октября 2011

Секрет в R заключается в векторизации.В вашем примере вы можете использовать cumprod для выполнения тяжелой работы:

z$NewVal2 <- x[1] * cumprod(with(z, 1 +(c(0, y[-1]/100))))

all.equal(z$NewVal, z$NewVal2)
[1] TRUE

head(z, 10)
    x y   NewVal  NewVal2
1  25 4 25.00000 25.00000
2  24 3 25.75000 25.75000
3  23 0 25.75000 25.75000
4  22 1 26.00750 26.00750
5  21 3 26.78773 26.78773
6  20 2 27.32348 27.32348
7  19 2 27.86995 27.86995
8  18 3 28.70605 28.70605
9  17 4 29.85429 29.85429
10 16 2 30.45138 30.45138

На моей машине цикл занимает всего менее 3 минут, в то время как оператор cumprod практически мгновенный.1006 *

6 голосов
/ 24 октября 2011

Я получил примерно 800-кратное улучшение с Reduce:

    system.time(z[, "NewVal"] <-Reduce("*",  c(1, 1+z$y[-1]/100), accumulate=T) )
   user  system elapsed 
  0.139   0.008   0.148 

> head(z)
    x y NewVal
1   1 1  1.000
2   2 1  1.010
3   3 1  1.020
4   4 5  1.071
5   5 1  1.082
6   6 2  1.103
7   7 2  1.126
8   8 3  1.159
9   9 0  1.159
10 10 1  1.171
> system.time(for(i in 2:nrow(z)){z$NewVal[i]=z$NewVal[i-1]+
                                              (z$NewVal[i-1]*(z$y[i]/100))})
   user  system elapsed 
  37.29  106.38  143.16 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...