给出一个data.frame和一个仅具有-1,0,1且长度等于data.frame列数的向量。是否存在一种自然的方法将向量转换为公式,而元素的位置-1出现在公式的左侧,而元素+1出现在公式的右侧?
例如,给定以下data.frame
df = data.frame(
'a' = rnorm(10),
'b' = rnorm(10),
'c' = rnorm(10),
'd' = rnorm(10),
'e' = rnorm(10))
及其后的向量vec = c(-1,-1,0,1,1)
。
是否存在一种自然的方式来构建公式a+b~d+e
?
答案 0 :(得分:1)
我们假设如果vec
中没有1,那么我们应该使用1的右手边,如果vec
中没有-1,那么左侧为空。
每个替代项都会生成一个字符串,但是如果需要公式类对象,请使用formula(s)
,其中s
是该字符串。
1)粘贴每侧子集化对应于vec -1的名称以给出LHS并粘贴/折叠它们,对vec 1进行相同的名称以给出RHS并将其粘贴〜一起。如果我们知道vec
中至少有一个1,则可以省略if
语句。在这里的解决方案中,这似乎是最简单的。
nms <- names(df)
LHS <- paste(nms[vec == -1], collapse = "+")
RHS <- paste(nms[vec == 1], collapse = "+")
if (RHS == "") RHS <- "1"
paste0(LHS, "~", RHS)
## [1] "a+b~d+e"
2)适当地:将LHS和RHS线交替合并为一个sapply
。如果我们知道vec
中至少有一个1,那么我们可以
通过省略if
语句来简化代码。这种方法比(1)短。
sa <- sapply(c(-1, 1), function(x) paste(names(df)[vec == x], collapse = "+"))
if (sa[2] == "") sa[2] <- "1"
paste0(sa[1], "~", sa[2])
## [1] "a+b~d+e"
3)轻按,我们可以像这样将LHS和RHS线交替组合成单个tapply
:
ta <- tapply(names(df), vec, paste, collapse = "+")
paste0(if (any(vec == -1)) ta[["-1"]], "~", if (any(vec == 1)) ta[["1"]] else 1)
## [1] "a+b~d+e"
如果我们知道-1和1在vec
中至少出现一次,那么我们可以将最后一行简化为:
paste0(ta[["-1"]], "~", ta[["1"]]])
## [1] "a+b~d+e"
总的来说,如果可以保证至少有一个1和至少一个-1,那么这种方法是最短的,但是与其他方法相比,处理边缘情况似乎有些麻烦。
答案 1 :(得分:0)
我们可以通过paste
paste(aggregate(nm ~ vec, subset(data.frame(nm = names(df), vec,
stringsAsFactors = FALSE), vec != 0),
FUN = paste, collapse= ' + ')[['nm']], collapse=' ~ ')
#[1] "a + b ~ d + e"
或者另一个选择是tapply
paste(tapply(names(df), vec, FUN = paste,
collapse= ' + ')[c('-1', '1')], collapse= ' ~ ')
#[1] "a + b ~ d + e"