模拟数据
df <- data.frame(posterior=rnorm(5), A=sample(c(T,F), 5, replace=T),
B=sample(c(T,F), 5, replace=T), C=sample(c(T,F), 5, replace=T) )
由此我希望产生一个包含2列的数据框:第一列是相同的,第二列是具有TRUE的所有变量(A,B或C)的名称。 (这是在变量选择的背景下完成的。)
我当前的解决方案在每个逻辑行上使用apply,然后按colnames(df[2:4])[row]
提取变量名列表。有更好的解决方案吗?
答案 0 :(得分:2)
这会创建您正在寻找的列,我相信:
df$Letters = apply(df[,2:4], 1, function(x) paste(names(x)[x], collapse=", "))
您可以使用df[,c("posterior", "Letters")]
答案 1 :(得分:2)
如果速度很重要,这里是一个矢量化解决方案,但它不是特别直观:
combs <- c("","A","B","AB","C","AC","BC","ABC") #all letter combinations in a binary order
transform(df, vars = combs[rowSums(t(t(df[2:4])*2^(0:2)))+1])
posterior A B C vars
1 1.28037818 TRUE TRUE FALSE AB
2 -0.07794835 FALSE TRUE FALSE B
3 0.86463032 FALSE FALSE TRUE C
4 -1.04609087 FALSE TRUE FALSE B
5 -1.13092499 TRUE TRUE TRUE ABC
基本上,您将行视为二进制数的表示,其中数字表示变量的存在或不存在。然后,您只需将此数字映射到组合向量。
修改强>
要自动生成梳子,您可以使用intToBits
和which
:
getCombs <- function(vars) c("", sapply(seq(2^length(vars)-1),
function(x) paste(vars[which(intToBits(x)==1)],collapse="")))
getCombs(LETTERS[1:3])
[1] "" "A" "B" "AB" "C" "AC" "BC" "ABC"
这需要不到一秒钟(在我的机器上)最多16个变量,每个附加变量的时间大约是两倍。这是因为在添加另一个变量时,组合数量会翻倍。
答案 2 :(得分:0)
我一直在花太多时间思考这个问题(因为我有类似的事情,我自己在做)。
我真的很喜欢詹姆斯的答案......但正如他所提到的,随着列数开始增加,它肯定会减慢很多。我也喜欢Senor O的直接apply
答案,这是一个很难被击败的答案。
这就是我想出来的。
logiNames <- function(inmatrix) {
if (!is.matrix(inmatrix)) inmatrix <- as.matrix(inmatrix)
if (is.null(colnames(inmatrix))) {
stop("The whole point of this is to work with colnames")
}
dims <- dim(inmatrix)
cn <- colnames(inmatrix)
if (!is.logical(inmatrix)) inmatrix <- as.logical(inmatrix)
M <- character(length(inmatrix))
M[inmatrix] <- rep(cn, each = dims[1])[inmatrix]
dim(M) <- dims
do.call(paste0, data.frame(M))
}
以下是几个例子......
示例数据:
set.seed(123)
ncol = 10
nrow = 10
m <- matrix(sample(c(TRUE, FALSE), ncol * nrow, TRUE), ncol = ncol,
dimnames=list(NULL, sample(c(letters, LETTERS), ncol, FALSE)))
n <- matrix(sample(c(1, 0), ncol * nrow, TRUE), ncol = ncol,
dimnames=list(NULL, sample(c(letters, LETTERS), ncol, FALSE)))
在logical
矩阵上:
m
# F q y U x P Q B s g
# [1,] TRUE FALSE FALSE FALSE TRUE TRUE FALSE FALSE TRUE TRUE
# [2,] FALSE TRUE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE
# [3,] TRUE FALSE FALSE FALSE TRUE FALSE TRUE FALSE TRUE TRUE
# [4,] FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE FALSE FALSE
# [5,] FALSE TRUE FALSE TRUE TRUE FALSE FALSE TRUE TRUE TRUE
# [6,] TRUE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
# [7,] FALSE TRUE FALSE FALSE TRUE TRUE FALSE TRUE FALSE FALSE
# [8,] FALSE TRUE FALSE TRUE TRUE FALSE FALSE FALSE FALSE TRUE
# [9,] FALSE TRUE TRUE TRUE TRUE FALSE FALSE TRUE FALSE TRUE
# [10,] TRUE FALSE TRUE TRUE FALSE TRUE TRUE TRUE TRUE FALSE
logiNames(m)
# [1] "FxPsg" "qxPQ" "FxQsg" "xPQB" "qUxBsg" "FUxPQBsg" "qxPB"
# [8] "qUxg" "qyUxBg" "FyUPQBs"
在零和一的矩阵上:
n
# z m k H c G q s K N
# [1,] 0 0 0 1 0 0 0 0 1 1
# [2,] 1 1 0 1 1 1 1 1 1 0
# [3,] 1 1 0 1 1 0 0 0 0 0
# [4,] 0 1 0 1 1 1 0 1 0 0
# [5,] 0 1 0 0 1 1 0 0 0 1
# [6,] 1 0 0 1 1 0 0 1 1 0
# [7,] 0 1 0 1 0 0 1 1 1 1
# [8,] 0 1 0 1 1 1 0 0 0 1
# [9,] 0 1 0 1 1 1 0 0 1 1
# [10,] 1 0 1 0 1 1 0 0 0 1
logiNames(n)
# [1] "HKN" "zmHcGqsK" "zmHc" "mHcGs" "mcGN" "zHcsK" "mHqsKN"
# [8] "mHcGN" "mHcGKN" "zkcGN"
当您处理包含大量 行 的数据时,这种情况的好处才会明显。例如,在上面的数据创建步骤中将“ncol”更改为20并将“nrow”更改为1e5,这给了我这些时间:
set.seed(123)
ncol = 20
nrow = 1e5
m <- matrix(sample(c(TRUE, FALSE), ncol * nrow, TRUE), ncol = ncol,
dimnames=list(NULL, sample(c(letters, LETTERS), ncol, FALSE)))
fun3 <- function() apply(m, 1, function(x) paste(colnames(m)[x], collapse=""))
system.time(fun3())
# user system elapsed
# 2.427 0.000 2.441
system.time(logiNames(m))
# user system elapsed
# 0.860 0.001 0.868