我想在data.frame上按行应用函数,以根据行中的值连接列标题。
df
A B
1 TRUE TRUE
2 FALSE TRUE
3 FALSE FALSE
A B Result
1 TRUE TRUE A / B
2 FALSE TRUE B
3 FALSE FALSE NA
我使用mutate()和rowwise()读过dplyr,但我不知道如何应用它们,因为列不是常量。
对于“i”行,我会做类似的事情:
paste(names(df)[as.logical(df[i,])], collapse = ' / ')
欢迎任何帮助。
谢谢。
答案 0 :(得分:6)
我建议不要在apply
上使用data.frame
(由于矩阵转换),尤其是边距为1(R中的行操作速度很慢)。相反,您可以非常轻松地在列上进行矢量化而无需矩阵转换,这是一个示例
res <- rep(NA_character_, nrow(df))
for(j in names(df)) res[df[[j]]] <- paste(res[df[[j]]], j, sep = " / ")
sub("NA / ", "", res, fixed = TRUE)
# [1] "A / B" "B" NA
以下是显示约X16改善的基准
set.seed(123)
N <- 1e5
df <- as.data.frame(matrix(sample(c(TRUE, FALSE), N*2, replace = TRUE), ncol = 2))
Rowwise <- function(df) apply(df, 1, FUN = function(x) paste(names(x)[x], collapse=" / "))
Colwise <- function(df) {
res <- rep(NA_character_, nrow(df));
for(j in names(df)) res[df[[j]]] <- paste(res[df[[j]]], j, sep = " / ");
sub("NA / ", "", res, fixed = TRUE)
}
microbenchmark::microbenchmark(Rowwise(df), Colwise(df))
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# Rowwise(df) 458.54526 502.43496 545.47028 548.42042 584.18000 669.6161 100 b
# Colwise(df) 27.11235 27.83873 34.65596 29.05341 32.83664 137.7905 100 a
答案 1 :(得分:3)
如果数据集不是很大(即数百万/数十亿行),我们可以使用apply
和MARGIN=1
来循环遍历行,使用names
向量的子集逻辑vector
作为索引,paste
将它们放在一起。在一行中编码更容易。
df$Result <- apply(df, 1, FUN = function(x) paste(names(x)[x], collapse=" / "))
但是,如果我们有一个大数据集,另一个选择是创建一个键/值对并通过匹配替换值,它比上述解决方案更快。
v1 <- do.call(paste, df)
unname(setNames(c("A / B", "B", "A", NA), do.call(paste,
expand.grid(rep(list(c(TRUE, FALSE)), 2))))[v1])
#[1] "A / B" "B" NA
或者我们可以使用算术运算来做到这一点
c(NA, "A", "B", "A / B")[1 + df[,1] + 2 * df[,2]]
#[1] "A / B" "B" NA
使用@ DavidArenburg的数据集并包含此处发布的两个解决方案(将'df'的列名更改为'A'和'B')
newPaste <- function(df) {
v1 <- do.call(paste, df)
unname(setNames(c("A / B", "B", "A", NA), do.call(paste,
expand.grid(rep(list(c(TRUE, FALSE)), 2))))[v1])
}
arith <- function(df){
c(NA, "A", "B", "A / B")[1 + df[,1] + 2 * df[,2]]
}
microbenchmark::microbenchmark(Rowwise(df), Colwise(df), newPaste(df),arith(df))
#Unit: milliseconds
# expr min lq mean median uq max neval
# Rowwise(df) 398.024791 453.68129 488.07312 481.051431 523.466771 688.36084 100
# Colwise(df) 25.361609 28.10300 34.20972 30.952365 35.885061 95.92575 100
# newPaste(df) 65.777304 69.07432 82.08602 71.606890 82.232980 176.66516 100
# arith(df) 1.790622 1.88339 4.74913 2.027674 4.753279 58.50942 100