Вот несколько подходов. (1) и (1а) кажутся лучшими, но другие показывают разные подходы. Они имеют те же имена столбцов и порядок, что и в вопросе, за исключением (1a) и (2), но их можно легко исправить, если это будет проблемой. Пакеты не используются, кроме (4a).
1) transform
ix <- grep("a", names(d))
cbind(d, setNames(d[ix] / d[-ix], sub("a", "c", names(d)[ix])))
## a_0 a_1 a_2 b_0 b_1 b_2 c_0 c_1 c_2
## 1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
## 2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.66667
1a) Это вариант (1) ;
transform(d, c = setNames(d[ix], ix-1) / d[-ix]) # ix is from above
## a_0 a_1 a_2 b_0 b_1 b_2 c.0 c.1 c.2
## 1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
## 2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.66667
2) изменить форму Преобразовать в длинную форму, выполнить деление и преобразовать обратно в широкую форму.
varying <- split(names(d), sub("_.*", "", names(d)))
long <- reshape(d, dir = "long", varying = varying, v.names = names(varying))
reshape(transform(long, c = a / b), dir = "wide", idvar = "id")[-1]
## a.1 b.1 c.1 a.2 b.2 c.2 a.3 b.3 c.3
## 1.1 10 0.30 33.33333 20 0.23 86.95652 25 0.34 73.52941
## 2.1 40 0.25 160.00000 20 0.40 50.00000 30 0.45 66.66667
3) применить Мы можем преобразовать в трехмерный массив, а затем использовать apply
.
nr <- nrow(d)
nc <- ncol(d)
cc <- apply(array(as.matrix(d), c(nr, nc / 2, 2)), 1:2, function(x) x[1] / x[2])
colnames(cc) <- paste("c", seq(0, length = ncol(cc)), sep = "_")
cbind(d, cc)
## a_0 a_1 a_2 b_0 b_1 b_2 c_0 c_1 c_2
## 1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
## 2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.66667
4) diff Транспонировать лог d
, брать дифференциалы и реверсировать транспонирование беру эксп транспонировать. Затем свяжите это с d
. Это решение предполагает, что все записи строго положительны (что имеет место в вопросе), так что мы можем взять журналы.
nc <- ncol(d)
cc <- t(exp(-diff(t(log(d)), nc/2)))
colnames(cc) <- paste("c", seq(0, length = ncol(cc)), sep = "_")
cbind(d, cc)
## a_0 a_1 a_2 b_0 b_1 b_2 c_0 c_1 c_2
## 1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
## 2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.66667
(4a) diff.zoo
поддерживает геометрию c diff, который выполняет деление, а не вычитание. (В текущей версии zoo diff.zoo
требует, чтобы элементы ввода были строго положительными, но это ограничение снято в версии разработки zoo.)
library(zoo)
nc <- ncol(d)
cc <- 1 / t(diff(zoo(t(d)), nc/2, arith = FALSE))
colnames(cc) <- paste("c", seq(0, length = ncol(cc)), sep = "_")
cbind(d, cc)
## a_0 a_1 a_2 b_0 b_1 b_2 c_0 c_1 c_2
## x.1 10 20 25 0.30 0.23 0.34 33.33333 86.95652 73.52941
## x.2 40 20 30 0.25 0.40 0.45 160.00000 50.00000 66.66667