Расчет% изменений с помощью By () - PullRequest
7 голосов
/ 28 июня 2011

Я неопытный пользователь R, боролся с функцией By () и был бы признателен за вашу помощь. Задача проста, у меня есть продольный набор данных (как я могу объявить один?) И мне нужно рассчитать различные показатели по идентификатору. Одна из метрик - это простое изменение в процентах (которое требует задержки, пример ниже):

 ID         Date          Temp        %Change
 AAA    1/1/2003    0.749881714 NA
 AAA    1/2/2003    0.666661576 -0.110977687
 AAA    1/3/2003    0.773079935 0.159628759
 AAA    1/4/2003    0.62902364  -0.186340751
 AAA    1/5/2003    0.733312374 0.165794619
 BBB    1/1/2003    0.707339766 NA
 BBB    1/2/2003    0.764986529 0.081497982
 BBB    1/3/2003    0.662201467 -0.134361925
 BBB    1/4/2003    0.774451765 0.169510798  
 BBB    1/5/2003    0.50829093  -0.343676453
 CCC    1/1/2003    0.836836215 NA
 CCC    1/2/2003    0.837136823 0.00035922
 CCC    1/3/2003    0.809016624 -0.033590924
 CCC    1/4/2003    0.690277509 -0.146769685
 CCC    1/5/2003    0.796357069 0.153676686

Интуитивно я понимаю использование By (), но не смог получить правильный результат (% Change), используя data.frame, который содержит $ ID, $ Date и $ Temp. Будем весьма благодарны за любые предложения о том, как достичь желаемого% изменения.

Ответы [ 3 ]

8 голосов
/ 28 июня 2011

Вы можете использовать комбинацию plyr для обработки группы с помощью операции с идентификатором, а quantmod имеет функцию для процентного изменения, названную Delt.

require(plyr)
require(quantmod)

> ddply(dat, "ID", transform,  DeltaCol = Delt(Temp))
    ID     Date      Temp    X.Change Delt.1.arithmetic
1  AAA 1/1/2003 0.7498817          NA                NA
2  AAA 1/2/2003 0.6666616 -0.11097769     -0.1109776868
3  AAA 1/3/2003 0.7730799  0.15962876      0.1596287574
4  AAA 1/4/2003 0.6290236 -0.18634075     -0.1863407501
5  AAA 1/5/2003 0.7333124  0.16579462      0.1657946178
6  BBB 1/1/2003 0.7073398          NA                NA
7  BBB 1/2/2003 0.7649865  0.08149798      0.0814979813
8  BBB 1/3/2003 0.6622015 -0.13436192     -0.1343619242
9  BBB 1/4/2003 0.7744518  0.16951080      0.1695107963
10 BBB 1/5/2003 0.5082909 -0.34367645     -0.3436764522
11 CCC 1/1/2003 0.8368362          NA                NA
12 CCC 1/2/2003 0.8371368  0.00035922      0.0003592196
13 CCC 1/3/2003 0.8090166 -0.03359092     -0.0335909235
14 CCC 1/4/2003 0.6902775 -0.14676969     -0.1467696849
15 CCC 1/5/2003 0.7963571  0.15367669      0.1536766860

Кроме того, вы можете пропустить бит plyr, вычислить дельту для всего data.frame, а затем обновить первую строку для каждого идентификатора. Есть много хороших идей по выбору первой строки data.frame на основе идентификатора здесь . Что-то вроде этого, вероятно, будет работать:

dat$Delta <- Delt(dat$Temp)
dat[ diff(c(0,dat$ID)) != 0, 5] <- NA

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

6 голосов
/ 28 июня 2011

Поскольку ОП специально спрашивал об использовании by(), я подумал, что предоставлю ответ, иллюстрирующий его использование.

Сначала вы пишете функцию, которая действует на каждый «фрагмент» фрейма данных:

myFun <- function(x){
n <- nrow(x)
x$Change <- c(NA,diff(x$Temp) / head(x$Temp,n-1))
x
}

Я использовал базовые функции diff для вычисления последовательных разностей в Temp, а затем, поскольку результирующий вектор имеет длину n-1, мы используем head, чтобы разделить различия на все, кроме последнего Temp значение. (Я сделал это только для работы head, поскольку это удобно; есть много других способов сделать это).

Тогда by вызов:

by(dat,dat$ID,FUN=myFun)

Если вы хотите снова собрать все части вместе, мы можем использовать do.call и rbind:

do.call(rbind,by(dat,dat$ID,FUN=myFun))
1 голос
/ 28 июня 2011

Ваш предложенный результат не "% change" (а скорее дробная разница), хотя это иллюстрирует метод, получающий "процент от оригинала", использующий начальное значение как основу для изменения:Вы хотите изменить интервал, вы можете разделить diff (x) на значения

> dat$pctTemp <-  unlist(tapply(dat$Temp, dat$ID, function(x) c(NA, 100*diff(x)/x[-length(x)]) )  )
> dat
    ID     Date      Temp      pctTemp
1  AAA 1/1/2003 0.7498817           NA
2  AAA 1/2/2003 0.6666616 -11.09776868
3  AAA 1/3/2003 0.7730799  15.96287574
4  AAA 1/4/2003 0.6290236 -18.63407501
5  AAA 1/5/2003 0.7333124  16.57946178
6  BBB 1/1/2003 0.7073398           NA
7  BBB 1/2/2003 0.7649865   8.14979813
snipped
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...