【问题标题】:Comparing Boolean Vectors比较布尔向量
【发布时间】:2011-12-14 02:23:03
【问题描述】:

我有一个数据框,其中包含四个逻辑向量 v1v2v3v4,它们是 TRUE或假。我需要根据布尔向量的组合(例如,"None""v1 only""v1 和v3”“全部”等)。我想在不获取数据框的子集或嵌套 ifelse 语句的情况下执行此操作。 对最好的方法有什么建议吗?谢谢!

【问题讨论】:

    标签: r boolean


    【解决方案1】:

    看来我参加这个聚会迟到了。不过,我不妨分享一下我带来的东西!

    这通过将FALSE/TRUE 的可能性视为位,并对它们进行操作以分配给v1v2v3 的每个组合一个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 &lt;- TRUE,然后尝试再次运行df$description &lt;- apply(df, 1, getDescription),则会出现以下错误:X * c(1, 2, 4) 中的错误:二进制运算符的非数字参数为什么会这样?谢谢!
    • @BoomShakalaka -- 这对我来说很好用。您是否可能分配了"TRUE" 而不是TRUE?您的错误消息暗示您的 data.frame 中的一列不是数字。或者,您的df 是否不止这三列?如果是这样,你需要做apply(df[c("v1", "v2", "v3")], 1, getDescription)。希望对您有所帮助。
    • 还有一个不是数字的列,所以这就是问题所在。谢谢!
    【解决方案2】:

    这是一种依赖于 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
    ....
    

    【讨论】:

    • +1 做得很好。另一个使用 0/1 表示的选项是将每个乘以 10 的幂并相加;这可以通过矩阵乘法来完成,例如as.matrix(dat) %*% 10^rev(seq_len(ncol(dat))-1)。 (如果您更喜欢二进制思维,也可以使用 2 的幂。)
    • +1 但我认为不需要“列索引”,因为它是由字符串中1s 的位置定义的。替代方案是 apply(1*dat,1,paste,collapse="")do.call(paste, c(1*dat,sep=""))
    • 谢谢。因此,基于您的答案,我正在考虑以下内容:v1 &lt;- ifelse(v1 == TRUE, 1000, 0)v2 &lt;- ifelse(v1 == TRUE, 100, 0)v3 &lt;- ifelse(v1 == TRUE, 10, 0)v4 &lt;- ifelse(v1 == TRUE, 1, 0)dat$v5 &lt;- sum(v1, v2, v3, v4) 然后我是否应该创建一个值列表来查找标签(例如 1111 == "All ") 还是有更好的方法?
    • @BoomShakalaka - 不确定我是否遵循了你的代码,但我认为我理解你需要完成什么。查看我的更新答案,如果我接近了,请告诉我。
    【解决方案3】:

    让我也把我的帽子扔进擂台

    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
    

    【讨论】:

    • 那顶帽子值得+1!正则表达式可以进一步完善这一点,用 , 替换除最后一个 and 之外的所有内容。这是应该起作用的东西:txt &lt;- "v1 and v2 and v3 and v4",然后是gsub("([[:space:]]and)(?![[:space:]]v[[:digit:]]$)", ",", txt, perl=TRUE)
    【解决方案4】:
     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
    

    【讨论】:

      猜你喜欢
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 2019-05-28
      • 2012-08-19
      • 2017-02-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多