如何根据多个条件语句创建多个新列?
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
,或 abd
,ab
,ac
,等等)
# 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()
会覆盖您的一些原始列。)
[第一个堆栈问题请客气:)
]
我正在基于现有列的多个条件语句在数据框中创建多个新列 - 所有本质上都是新的列组合。
例如,如果有 4 列 (a:d),我需要所有组合(abcd、abc、abd 等)的新列和基于 [= 中阈值数据的 0/1 编码30=].
包含玩具数据示例和期望的结果。但是需要可扩展:有 4 个基列,但我需要 2、3 和 4 列的所有组合,而不仅仅是 3 值(abc、abd、.... ab、ac、ad、...总 n = 11)
[上下文背景:这实际上是来自多能干细胞的流式细胞术数据,这些干细胞可以生长成所有谱系细胞类型的集落(多能,或 abcd
)或逐渐受到限制的群体(仅 abc
,或 abd
,ab
,ac
,等等)
# 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()
会覆盖您的一些原始列。)