Вы можете использовать by
и reshape
, чтобы перевести USD в широкоформатный формат, опуская столбец var3
.
b <- by(df1, df1$id, reshape, direction="wide", timevar="method.of.payment", drop="var3")
b <- Reduce(function(x, y) merge(x, y, all=TRUE), b) # merge the list resulting from `by`
Чтобы свернуть уровни, вы можете использовать toString
в другомby
и cbind
к объединенному
res <- cbind(b, do.call(rbind, by(df1[c(2, 4)], df1$id, function(X)
lapply(X, function(x) toString(na.omit(x))))))[c(1, 6, 2:4, 7)] # some column sorting
res
# id method.of.payment usd.cash usd.liabilities usd.shares var3
# 1 1 cash, liabilities, shares 110 130 200 1500
# 2 2 cash 100 NA NA ab, bc
Редактировать: Возможно, это более элегантно сделать всего за один by
.
b <- by(df1, df1$id, function(X) {
r <- reshape(X, direction="wide", timevar="method.of.payment", drop="var3")
s <- lapply(X[c(2, 4)], function(x) toString(na.omit(x)))
return(merge(r, s))
})
res <- Reduce(function(x, y) merge(x, y, all=TRUE), b)[c(1, 3, 2, 5:6, 4)]
res
# id method.of.payment usd.cash usd.liabilities usd.shares var3
# 1 1 cash, liabilities, shares 110 130 200 1500
# 2 2 cash 100 NA NA ab, bc
Данные
Примечание: Лучше избегать пробелов в именах столбцов в R.
df1 <- structure(list(id = c(1, 1, 1, 2, 2), method.of.payment = structure(c(1L,
2L, 3L, 1L, NA), .Label = c("cash", "liabilities", "shares"), class = "factor"),
usd = c(110, 130, 200, 100, NA), var3 = structure(c(1L, NA,
NA, 2L, 3L), .Label = c("1500", "ab", "bc"), class = "factor")), class = "data.frame", row.names = c(NA,
-5L))