如何根据多个条件语句创建多个新列?

How to create multiple new columns based on multiple conditional statements?

[第一个堆栈问题请客气:)]

我正在基于现有列的多个条件语句在数据框中创建多个新列 - 所有本质上都是新的列组合。

例如,如果有 4 列 (a:d),我需要所有组合(abcd、abc、abd 等)的新列和基于 [= 中阈值数据的 0/1 编码30=].

包含玩具数据示例和期望的结果。但是需要可扩展:有 4 个基列,但我需要 2、3 和 4 列的所有组合,而不仅仅是 3 值(abc、abd、.... ab、ac、ad、...总 n = 11)

[上下文背景:这实际上是来自多能干细胞的流式细胞术数据,这些干细胞可以生长成所有谱系细胞类型的集落(多能,或 abcd)或逐渐受到限制的群体(仅 abc,或 abdabac,等等)

# Toy data set
set.seed(123)
df <- tibble(a = c(sample(10:50, 10)),
             b = c(sample(10:50, 10)),
             c = c(sample(10:50, 10)),
             d = c(sample(10:50, 10)))

当前代码产生了预期的结果,但是,这需要 11 行重复代码,容易出错,我希望有更优雅的解决方案:

df %>% 
  mutate(
    abcd = if_else(a > 30 & b > 20 & c > 30 & d > 30, 1, 0),
    abc = if_else(a > 30 & b > 20 & c > 30 & d <= 30, 1, 0),
    abd = if_else(a > 30 & b > 20 & c <= 30 & d > 30, 1, 0),
    acd = if_else(a > 30 & b <= 20 & c > 30 & d > 30, 1, 0),
    bcd = if_else(a <= 30 & b > 20 & c > 30 & d > 30, 1, 0))

我从你的问题中了解到,对于每一行,你只需要找到哪些列满足你的 ifelse() 条件中定义的条件。此矢量化解决方案将向您的 df 添加一列,其中包含所有组合。这也可能比多个 ifelse 条件更快。最后,新列可用于排序或分组。

# define the threshold levels for all columns
threshold = c(a=30, b=20, c=30, d=30)

# get names of columns meeting the threshold and paste names
df$combn <- apply(df, 1, function(x) {
  paste(names(x)[x > threshold], collapse = "")
})

> df
# A tibble: 10 x 5
       a     b     c     d combn
   <int> <int> <int> <int> <chr>
 1    21    49    46    49 bcd  
 2    41    28    37    46 abcd 
 3    25    36    34    36 bcd  
 4    43    31    47    40 abcd 
 5    44    13    48    10 ac   
 6    11    42    35    27 bc   
 7    28    18    29    48 d    
 8    40    11    30    17 a    
 9    46    20    19    20 a    
10    24    40    14    43 bd   

如果我没记错的话,您希望将每一行准确地归为一个 class,因此将类别名称作为阈值测试的串联就足够了。然后你可以使用 spread():

得到 0/1
df %>% 
  mutate(
    a_ = if_else(a > 30, 'a', 'x'),
    b_ = if_else(b > 20, 'b', 'x'),
    c_ = if_else(c > 30, 'c', 'x'),
    d_ = if_else(d > 30, 'd', 'x'),
    all_ = paste0(a_, b_, c_, d_),
    one_ = 1) %>% 
  spread(all_, one_, fill = 0) %>% 
  select(-ends_with("_"))

给予

# A tibble: 10 x 11
       a     b     c     d  abcd  axcx  axxx  xbcd  xbcx  xbxd  xxxd
   <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1    11    42    35    27     0     0     0     0     1     0     0
 2    21    49    46    49     0     0     0     1     0     0     0
 3    24    40    14    43     0     0     0     0     0     1     0
 4    25    36    34    36     0     0     0     1     0     0     0
 5    28    18    29    48     0     0     0     0     0     0     1
 6    40    11    30    17     0     0     1     0     0     0     0
 7    41    28    37    46     1     0     0     0     0     0     0
 8    43    31    47    40     1     0     0     0     0     0     0
 9    44    13    48    10     0     1     0     0     0     0     0
10    46    20    19    20     0     0     1     0     0     0     0

(您可以使用 '' 而不是 'x',但是 spread() 会覆盖您的一些原始列。)