Как эффективно разделить преемника на предшественника в каждом столбце фрейма данных

У меня есть dataframe myDF, созданный вот так:

a <- 1:4
b <- seq(3, 16, length=4)
myDF <- data.frame(a=a, b=b)

что выглядит так:

  a         b
1 1  3.000000
2 2  7.333333
3 3 11.666667
4 4 16.000000

Теперь я хочу разделить последовательно предшественника и преемника в каждом столбце, добавить результаты в существующий фрейм данных, заменить одно отсутствующее значение в каждом столбце на NA и добавить новые имена столбцов. В приведенном выше примере желаемый результат выглядит так:

  a         b     amod     bmod
1 1  3.000000       NA       NA
2 2  7.333333 2.000000 2.444444
3 3 11.666667 1.500000 1.590909
4 4 16.000000 1.333333 1.371429

Итак, в столбце a 2 делится на 1, 3 делится на 2, а 4 делится на 3, а результаты сохраняются в amod.

Я делаю это сейчас так:

divStuff <-function(aCol){

  newCol <- aCol[2:length(aCol)]/aCol[1:length(aCol) - 1]
  newCol <- c(NA, newCol)

  return(newCol)
}
newDF <- data.frame(lapply(myDF, divStuff))
names(newDF) <- paste(names(myDF), "mod", sep="")
endDF <- cbind(myDF, newDF)

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

Теперь мне интересно, можно ли это сделать так или есть более разумный способ выполнения таких операций, которые, например, избегайте вызова cbind или выполняет cbind таким образом, чтобы избежать строки newCol <- c(NA, newCol) путем автоматического добавления NA. Я не нашел хорошего способа, все решения для этого выглядят похоже на этот.


person Cleb    schedule 02.09.2015    source источник


Ответы (2)


С base R:

myDF[,paste0(names(myDF), "mod")] <- sapply(myDF, function(x) c(NA, x[-1]/head(x,-1)))
#  a         b     amod     bmod
#1 1  3.000000       NA       NA
#2 2  7.333333 2.000000 2.444444
#3 3 11.666667 1.500000 1.590909
#4 4 16.000000 1.333333 1.371429
person Pierre L    schedule 02.09.2015
comment
Возможно paste0(names(myDF), "mod") будет более общим - person David Arenburg; 02.09.2015
comment
Отлично, отлично работает! Я поддерживаю его сейчас и, возможно, приму его позже. - person Cleb; 02.09.2015

Вот быстрая data.table версия (с использованием версии для разработки в GH)

library(data.table) ## V 1.9.5
setDT(myDF)[, paste0(names(myDF), "mod") := lapply(.SD, function(x) x/shift(x))]
#    a         b     amod     bmod
# 1: 1  3.000000       NA       NA
# 2: 2  7.333333 2.000000 2.444444
# 3: 3 11.666667 1.500000 1.590909
# 4: 4 16.000000 1.333333 1.371429

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

library(dplyr)
myDF %>% 
  mutate_each(funs(./lag(.))) %>%
  cbind(myDF, .)
#   a         b        a        b
# 1 1  3.000000       NA       NA
# 2 2  7.333333 2.000000 2.444444
# 3 3 11.666667 1.500000 1.590909
# 4 4 16.000000 1.333333 1.371429
person David Arenburg    schedule 02.09.2015
comment
Это больше похоже на то, что я имел в виду такую ​​«простую» задачу. Я пробую это сделать после того, как обновлю свою версию R; с моим я сталкиваюсь с проблемами зависимости. Но уже большое спасибо за вклад! - person Cleb; 02.09.2015
comment
Также отлично работает! Первое решение также требует пакетов magic, которые содержат функцию shift; может ты сможешь обновить свой пост !? Поскольку это хорошее и рабочее решение, я поддерживаю его, но приму решение Пьера Лафортуна, поскольку оно не требует дополнительных пакетов. - person Cleb; 02.09.2015
comment
Если вы хотите avoud shift, вы можете просто setDT(myDF)[, paste0(names(myDF), "mod") := lapply(.SD, function(x) x/c(NA, x[-.N]))] - person David Arenburg; 02.09.2015
comment
Хорошо спасибо! Мог многому научиться из вашего ответа! Комментарий о «магии» был больше для других людей, которые хотят воспроизвести ваш результат; Я нашел это быстро, но другие могут не найти. - person Cleb; 03.09.2015
comment
К пакету data.table, но не к «волшебству», или я что-то упускаю? - person Cleb; 03.09.2015
comment
Чтобы разрабатываемая версия на GH - person David Arenburg; 03.09.2015
comment
Хорошо, теперь я вижу; У меня действительно версия 1.9.4, а у вас 1.9.5 - моя вина, тогда все должно быть в порядке. - person Cleb; 03.09.2015