使用数值条件对一系列列进行编码
Coding a series of columns with a numerical condition
我有一系列数字列,范围从 0 到 8。我想在一行仅一次报告 3 或更多时生成一个二项式变量,而不是编码为“高”,否则为“低”。
structure(list(AE_1 = c(0L, 1L, 0L, 0L, 0L, 2L, 0L), AE_2 = c(0L,
1L, 2L, 1L, 0L, 0L, 0L), AE_3 = c(1L, 4L, 1L, 8L, 0L, 8L, 1L),
AE_4 = c(0L, 1L, 1L, 0L, 0L, 0L, 0L), AE_5 = c(0L, 0L, 1L,
1L, 0L, 0L, 1L), AE_6 = c(0L, 5L, 1L, 3L, 0L, 4L, 1L), AE_7 = c(0L,
1L, 1L, 1L, 0L, 2L, 0L), AE_8 = c(0L, 2L, 1L, 2L, 0L, 0L,
0L), new_AE = c("low", "low", "low", "low", "low", "low",
"low")), class = "data.frame", row.names = c(NA, -7L))
我有这段代码,所有行的结果都很低。
df<-df%>%
mutate(new_AE= pmap_chr(select(., starts_with('AE')), ~
case_when(any(c(...) <= 2) ~ "low" , any(c(...) >=3) ~ "high")))
虽然我想要这样的东西:
问题是第一个条件的 case_when
全部为真,因此我们只得到 'low' 值。在这里,我们甚至不需要 case_when
因为只有两个类别,这可以通过将逻辑索引转换为数字索引并替换为标签向量来创建
library(dplyr)
df %>%
rowwise %>%
mutate(new_AE = c('low', 'high')[1+ any(c_across(where(is.numeric)) >=3)]) %>%
ungroup
-输出
# A tibble: 7 x 9
# AE_1 AE_2 AE_3 AE_4 AE_5 AE_6 AE_7 AE_8 new_AE
# <int> <int> <int> <int> <int> <int> <int> <int> <chr>
#1 0 0 1 0 0 0 0 0 low
#2 1 1 4 1 0 5 1 2 high
#3 0 2 1 1 1 1 1 1 low
#4 0 1 8 0 1 3 1 2 high
#5 0 0 0 0 0 0 0 0 low
#6 2 0 8 0 0 4 2 0 high
#7 0 0 1 0 1 1 0 0 low
或者使用 base R
中的 rowSums
可以更轻松地完成此操作
df$new_AE <- c("low", "high")[(!!rowSums(df >= 3)) + 1]
df$new_AE
#[1] "low" "high" "low" "high" "low" "high" "low"
在应用case_when
时必须考虑逻辑语句的顺序或确保在后续表达式中进行更正。如果我们测试 OP 的第二个数据
v1 <- c(1, 1, 4, 1, 0, 5, 1)
any(v1 <= 2)
#[1] TRUE
这是case_when
中的第一个表达式。由于第一个已经执行并找到匹配项,因此不执行后续表达式
case_when(any(v1 <=2) ~ 'low', any(v1 >=3) ~ 'high')
#[1] "low"
通过颠倒顺序,我们得到“高”
case_when( any(v1 >=3) ~ 'high', any(v1 <=2) ~ 'low')
#[1] "high"
所以,确定哪个更优先,并根据那个设置这些表达式的顺序
更新
我对我的解决方案稍作修改,因为 new_AE
列从一开始就存在,只是值不正确所以这里还有另一种解决方案,以防万一您想一次性使用 pmap
.但是,您已经收到了一些很棒的解决方案。
library(dplyr)
library(purrr)
df %>%
mutate(new_AE = pmap(df %>%
select(-9), ~ ifelse(any(c(...) >= 3), "high", "low")))
AE_1 AE_2 AE_3 AE_4 AE_5 AE_6 AE_7 AE_8 new_AE
1 0 0 1 0 0 0 0 0 low
2 1 1 4 1 0 5 1 2 high
3 0 2 1 1 1 1 1 1 low
4 0 1 8 0 1 3 1 2 high
5 0 0 0 0 0 0 0 0 low
6 2 0 8 0 0 4 2 0 high
7 0 0 1 0 1 1 0 0 low
这可以通过使用 pmax
检查 base R 中每一行的最大值来轻松完成。现在当然,您不会将 8 个列名写入 pmax
,所以这样做。
df[,9] <- c("low", "high")[ 1 + (do.call(pmax, df[,-9]) >= 3)]
> df
AE_1 AE_2 AE_3 AE_4 AE_5 AE_6 AE_7 AE_8 new_AE
1 0 0 1 0 0 0 0 0 low
2 1 1 4 1 0 5 1 2 high
3 0 2 1 1 1 1 1 1 low
4 0 1 8 0 1 3 1 2 high
5 0 0 0 0 0 0 0 0 low
6 2 0 8 0 0 4 2 0 high
7 0 0 1 0 1 1 0 0 low
根据您想要的条件查看 [] returns true/false 中的表达式
# this returns max of each row
do.call(pmax, df[,-9])
[1] 1 5 2 8 0 8 1
# this checks whether max of each row is 3 or more
do.call(pmax, df[,-9]) >= 3
[1] FALSE TRUE FALSE TRUE FALSE TRUE FALSE
因此,如果您不习惯使用此策略,可以改用 replace
df$new_AE <- replace(df$new_AE, do.call(pmax, df[,-9]) >= 3, "high")
我有一系列数字列,范围从 0 到 8。我想在一行仅一次报告 3 或更多时生成一个二项式变量,而不是编码为“高”,否则为“低”。
structure(list(AE_1 = c(0L, 1L, 0L, 0L, 0L, 2L, 0L), AE_2 = c(0L,
1L, 2L, 1L, 0L, 0L, 0L), AE_3 = c(1L, 4L, 1L, 8L, 0L, 8L, 1L),
AE_4 = c(0L, 1L, 1L, 0L, 0L, 0L, 0L), AE_5 = c(0L, 0L, 1L,
1L, 0L, 0L, 1L), AE_6 = c(0L, 5L, 1L, 3L, 0L, 4L, 1L), AE_7 = c(0L,
1L, 1L, 1L, 0L, 2L, 0L), AE_8 = c(0L, 2L, 1L, 2L, 0L, 0L,
0L), new_AE = c("low", "low", "low", "low", "low", "low",
"low")), class = "data.frame", row.names = c(NA, -7L))
df<-df%>%
mutate(new_AE= pmap_chr(select(., starts_with('AE')), ~
case_when(any(c(...) <= 2) ~ "low" , any(c(...) >=3) ~ "high")))
虽然我想要这样的东西:
问题是第一个条件的 case_when
全部为真,因此我们只得到 'low' 值。在这里,我们甚至不需要 case_when
因为只有两个类别,这可以通过将逻辑索引转换为数字索引并替换为标签向量来创建
library(dplyr)
df %>%
rowwise %>%
mutate(new_AE = c('low', 'high')[1+ any(c_across(where(is.numeric)) >=3)]) %>%
ungroup
-输出
# A tibble: 7 x 9
# AE_1 AE_2 AE_3 AE_4 AE_5 AE_6 AE_7 AE_8 new_AE
# <int> <int> <int> <int> <int> <int> <int> <int> <chr>
#1 0 0 1 0 0 0 0 0 low
#2 1 1 4 1 0 5 1 2 high
#3 0 2 1 1 1 1 1 1 low
#4 0 1 8 0 1 3 1 2 high
#5 0 0 0 0 0 0 0 0 low
#6 2 0 8 0 0 4 2 0 high
#7 0 0 1 0 1 1 0 0 low
或者使用 base R
rowSums
可以更轻松地完成此操作
df$new_AE <- c("low", "high")[(!!rowSums(df >= 3)) + 1]
df$new_AE
#[1] "low" "high" "low" "high" "low" "high" "low"
在应用case_when
时必须考虑逻辑语句的顺序或确保在后续表达式中进行更正。如果我们测试 OP 的第二个数据
v1 <- c(1, 1, 4, 1, 0, 5, 1)
any(v1 <= 2)
#[1] TRUE
这是case_when
中的第一个表达式。由于第一个已经执行并找到匹配项,因此不执行后续表达式
case_when(any(v1 <=2) ~ 'low', any(v1 >=3) ~ 'high')
#[1] "low"
通过颠倒顺序,我们得到“高”
case_when( any(v1 >=3) ~ 'high', any(v1 <=2) ~ 'low')
#[1] "high"
所以,确定哪个更优先,并根据那个设置这些表达式的顺序
更新
我对我的解决方案稍作修改,因为 new_AE
列从一开始就存在,只是值不正确所以这里还有另一种解决方案,以防万一您想一次性使用 pmap
.但是,您已经收到了一些很棒的解决方案。
library(dplyr)
library(purrr)
df %>%
mutate(new_AE = pmap(df %>%
select(-9), ~ ifelse(any(c(...) >= 3), "high", "low")))
AE_1 AE_2 AE_3 AE_4 AE_5 AE_6 AE_7 AE_8 new_AE
1 0 0 1 0 0 0 0 0 low
2 1 1 4 1 0 5 1 2 high
3 0 2 1 1 1 1 1 1 low
4 0 1 8 0 1 3 1 2 high
5 0 0 0 0 0 0 0 0 low
6 2 0 8 0 0 4 2 0 high
7 0 0 1 0 1 1 0 0 low
这可以通过使用 pmax
检查 base R 中每一行的最大值来轻松完成。现在当然,您不会将 8 个列名写入 pmax
,所以这样做。
df[,9] <- c("low", "high")[ 1 + (do.call(pmax, df[,-9]) >= 3)]
> df
AE_1 AE_2 AE_3 AE_4 AE_5 AE_6 AE_7 AE_8 new_AE
1 0 0 1 0 0 0 0 0 low
2 1 1 4 1 0 5 1 2 high
3 0 2 1 1 1 1 1 1 low
4 0 1 8 0 1 3 1 2 high
5 0 0 0 0 0 0 0 0 low
6 2 0 8 0 0 4 2 0 high
7 0 0 1 0 1 1 0 0 low
根据您想要的条件查看 [] returns true/false 中的表达式
# this returns max of each row
do.call(pmax, df[,-9])
[1] 1 5 2 8 0 8 1
# this checks whether max of each row is 3 or more
do.call(pmax, df[,-9]) >= 3
[1] FALSE TRUE FALSE TRUE FALSE TRUE FALSE
因此,如果您不习惯使用此策略,可以改用 replace
df$new_AE <- replace(df$new_AE, do.call(pmax, df[,-9]) >= 3, "high")