[第一堆问题请亲切的:)
]
我正在基于现有列的多个条件语句在数据框中创建多个新列 - 所有基本上是新的列组合。
例如,如果有4列(a:d),我需要所有组合的新列(abcd,abc,abd等)和基于阈值数据的0/1编码:d。
包括玩具数据示例和期望的结果。但是需要可扩展:有4个基本列,但我需要2,3和4列的所有组合,而不仅仅是3个值(abc,abd,.... ab,ac,ad,... total 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
如果我正确地得到了这个,你想要将每一行分类为一个类,所以将类别名称作为阈值测试的连接就足够了。然后你可以使用0/1
获得spread()
列:
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()
将覆盖您的一些原始列。)