【发布时间】:2011-12-14 02:23:03
【问题描述】:
我有一个数据框,其中包含四个逻辑向量 v1、v2、v3、v4,它们是 TRUE或假。我需要根据布尔向量的组合(例如,"None"、"v1 only"、"v1 和v3”、“全部”等)。我想在不获取数据框的子集或嵌套 ifelse 语句的情况下执行此操作。 对最好的方法有什么建议吗?谢谢!
【问题讨论】:
我有一个数据框,其中包含四个逻辑向量 v1、v2、v3、v4,它们是 TRUE或假。我需要根据布尔向量的组合(例如,"None"、"v1 only"、"v1 和v3”、“全部”等)。我想在不获取数据框的子集或嵌套 ifelse 语句的情况下执行此操作。 对最好的方法有什么建议吗?谢谢!
【问题讨论】:
看来我参加这个聚会迟到了。不过,我不妨分享一下我带来的东西!
这通过将FALSE/TRUE 的可能性视为位,并对它们进行操作以分配给v1、v2 和v3 的每个组合一个1 到8 之间的唯一整数(很像chmod可以表示*NIX 系统上的权限位)。然后将整数用作索引来选择文本描述符向量的适当元素。
(为了演示,我只使用了三列,但这种方法可以很好地扩展。)
# CONSTRUCT VECTOR OF DESCRIPTIONS
description <- c("None", "v1", "v2", "v1 and v2",
"v3", "v1 and v3", "v2 and v3", "All")
# DEFINE DESCRIPTION FUNCTION
getDescription <- function(X) {
index <- 1 + sum(X*c(1,2,4))
description[index]
}
# TRY IT OUT ON ALL COMBOS OF v1, v2, and v3
df <- expand.grid(v1=c(FALSE, TRUE),
v2=c(FALSE, TRUE),
v3=c(FALSE, TRUE))
df$description <- apply(df, 1, getDescription)
# YEP, IT WORKS.
df
# v1 v2 v3 description
# 1 FALSE FALSE FALSE None
# 2 TRUE FALSE FALSE v1
# 3 FALSE TRUE FALSE v2
# 4 TRUE TRUE FALSE v1 and v2
# 5 FALSE FALSE TRUE v3
# 6 TRUE FALSE TRUE v1 and v3
# 7 FALSE TRUE TRUE v2 and v3
# 8 TRUE TRUE TRUE All
【讨论】:
df$v3 <- TRUE,然后尝试再次运行df$description <- apply(df, 1, getDescription),则会出现以下错误:X * c(1, 2, 4) 中的错误:二进制运算符的非数字参数为什么会这样?谢谢!
"TRUE" 而不是TRUE?您的错误消息暗示您的 data.frame 中的一列不是数字。或者,您的df 是否不止这三列?如果是这样,你需要做apply(df[c("v1", "v2", "v3")], 1, getDescription)。希望对您有所帮助。
这是一种依赖于 TRUE / FALSE 可以表示为 0 和 1 的事实的方法。您可以将布尔值乘以其列索引,然后将所有值粘贴在一起。这将告诉您哪些列的每一行的值为 1。这是一个例子:
set.seed(1)
dat <- data.frame(v1 = sample(c(T,F), 10, TRUE),
v2 = sample(c(T,F), 10, TRUE),
v3 = sample(c(T,F), 10, TRUE),
v4 = sample(c(T,F), 10, TRUE)
)
#End fake data
#Multiple T/F times the column index
dat <- dat * rep(seq_len(ncol(dat)), each = nrow(dat))
#Paste together in a new column
dat$v5 <- apply(dat, 1, function(x) paste(x, collapse = ""))
> dat
v1 v2 v3 v4 v5
1 0 0 3 4 0034
2 0 2 0 4 0204
...
结合以下有用的 cmets 和附加问题
我会使用expand.grid() 创建一个查找表,然后编写文本标签来表示它们,但你认为合适。这是一个包含两列的示例:
set.seed(1)
dat <- data.frame(v1 = sample(c(T,F), 10, TRUE),
v2 = sample(c(T,F), 10, TRUE)
)
#Thanks @Joshua
dat$comp <- as.character(apply(1 * dat, 1, paste, collapse=""))
#Look up table
lookup <- data.frame(comp = apply(expand.grid(0:1, 0:1), 1, paste, collapse = ""),
text = c("none", "v1 only", "v2 only", "all"),
stringsAsFactors = FALSE
)
#Use merge to join the look up table to your data. Note the consistent naming of the comp column
> merge(dat, lookup)
comp v1 v2 text
1 00 FALSE FALSE none
2 00 FALSE FALSE none
3 01 FALSE TRUE v2 only
....
【讨论】:
as.matrix(dat) %*% 10^rev(seq_len(ncol(dat))-1)。 (如果您更喜欢二进制思维,也可以使用 2 的幂。)
1s 的位置定义的。替代方案是 apply(1*dat,1,paste,collapse="") 或 do.call(paste, c(1*dat,sep=""))。
v1 <- ifelse(v1 == TRUE, 1000, 0)v2 <- ifelse(v1 == TRUE, 100, 0)v3 <- ifelse(v1 == TRUE, 10, 0)v4 <- ifelse(v1 == TRUE, 1, 0)dat$v5 <- sum(v1, v2, v3, v4) 然后我是否应该创建一个值列表来查找标签(例如 1111 == "All ") 还是有更好的方法?
让我也把我的帽子扔进擂台
plyr::adply(dat, 1, function(x) paste(names(Filter(isTRUE, x)), collapse = " and "))
v1 v2 v3 v4 V1
1 TRUE TRUE FALSE TRUE v1 and v2 and v4
2 TRUE TRUE TRUE FALSE v1 and v2 and v3
3 FALSE FALSE FALSE TRUE v4
4 FALSE TRUE TRUE TRUE v2 and v3 and v4
5 TRUE FALSE TRUE FALSE v1 and v3
6 FALSE TRUE TRUE FALSE v2 and v3
7 FALSE FALSE TRUE FALSE v3
8 FALSE FALSE TRUE TRUE v3 and v4
9 FALSE TRUE FALSE FALSE v2
10 TRUE FALSE TRUE TRUE v1 and v3 and v4
【讨论】:
, 替换除最后一个 and 之外的所有内容。这是应该起作用的东西:txt <- "v1 and v2 and v3 and v4",然后是gsub("([[:space:]]and)(?![[:space:]]v[[:digit:]]$)", ",", txt, perl=TRUE)。
set.seed(123)
> dat <- data.frame(v1 = sample(c(T,F), 10, TRUE),
+ v2 = sample(c(T,F), 10, TRUE),
+ v3 = sample(c(T,F), 10, TRUE),
+ v4 = sample(c(T,F), 10, TRUE)
+ )
> dat
第一种策略使用各种模式组合来索引字符向量,默认为 1 来索引“Other”:
> dat$bcateg <- c("Other", "v2 only", "v1 and v3", "All")[1+
+ with(dat, 1*(v2 & !v1 &!v3 &!v4))
+ +with(dat, 2*(v1&v3))+
+ with(dat, v1&v2&v3&v4)]
> dat
v1 v2 v3 v4 bcateg
1 TRUE FALSE FALSE FALSE Other
2 FALSE TRUE FALSE FALSE v2 only
3 TRUE FALSE FALSE FALSE Other
4 FALSE FALSE FALSE FALSE Other
5 FALSE TRUE FALSE TRUE Other
6 TRUE FALSE FALSE TRUE Other
7 FALSE TRUE FALSE FALSE v2 only
8 FALSE TRUE FALSE TRUE Other
9 FALSE TRUE TRUE TRUE Other
10 TRUE FALSE TRUE TRUE v1 and v3
第二种策略使用“,”分隔符连接 TRUE 的列名:
> dat$bcateg2 <-paste( c("","v1")[dat[["v1"]]+1 ], c("","v2")[dat[["v2"]]+1 ], c("","v3")[dat[["v3"]]+1 ], c("","v4")[dat[["v4"]]+1 ], sep = ",")
> dat
v1 v2 v3 v4 bcateg bcateg2
1 TRUE FALSE FALSE FALSE Other v1,,,
2 FALSE TRUE FALSE FALSE v2 only ,v2,,
3 TRUE FALSE FALSE FALSE Other v1,,,
4 FALSE FALSE FALSE FALSE Other ,,,
5 FALSE TRUE FALSE TRUE Other ,v2,,v4
6 TRUE FALSE FALSE TRUE Other v1,,,v4
7 FALSE TRUE FALSE FALSE v2 only ,v2,,
8 FALSE TRUE FALSE TRUE Other ,v2,,v4
9 FALSE TRUE TRUE TRUE Other ,v2,v3,v4
10 TRUE FALSE TRUE TRUE v1 and v3 v1,,v3,v4
【讨论】: