输出值与 R 中的特定数字匹配的所有列名
Output all column names where the value matches a specific number in R
我有一个关于患者是否符合研究标准的数据框,每一行是一个患者,每一列是一个标准。所以有些列是纳入标准,有些列是排除标准,我想输出不合格的原因。例如,
test <- data.frame(A = c(0, 0, 1),
B = c(0, 0, 0),
C = c(0, 1, 1),
D = c(1, 0, 0),
E = c(1, 0, 1))
其中 A、B、C 是包含标准,D、E 是排除标准,如果包含标准 == 0 或排除标准 == 1,我想输出列名(可能不止一个) .
预期输出为
output <- data.frame(A = c(0, 0, 1),
B = c(0, 0, 0),
C = c(0, 1, 1),
D = c(1, 0, 0),
E = c(1, 0, 1),
failed_incl = c("A, B, C", "A, B", "B"),
failed_excl = c("D, E", "", "E"))
有没有一种方法可以高效地做到这一点而不必写出所有可能的场景?实际数据框有更多的列。
有多种方式。一种选择是使用 apply
遍历行 (MARGIN = 1
),将逻辑向量 (x== 0
) 的 names
和 paste
放在一起
test$failed_incl <- apply(test[1:3], 1, function(x) toString(names(x)[x == 0]))
test$failed_excl <- apply(test[4:5], 1, function(x) toString(names(x)[x == 1]))
-输出
test
# A B C D E failed_incl failed_excl
#1 0 0 0 1 1 A, B, C D, E
#2 0 0 1 0 0 A, B
#3 1 0 1 0 1 B E
或使用tidyverse
library(dplyr)
test %>%
rowwise %>%
mutate(failed_incl = toString(names(.)[which(c_across(A:C) == 0)]),
failed_excl = toString(c('D', 'E')[which(c_across(D:E) == 1)])) %>%
ungroup
# A tibble: 3 x 7
# A B C D E failed_incl failed_excl
# <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
#1 0 0 0 1 1 A, B, C "D, E"
#2 0 0 1 0 0 A, B ""
#3 1 0 1 0 1 B "E"
这里有一个 tidyverse 方法,它旋转列名,然后根据 inclusion/exclusion 条件进行汇总:
failed_df <-
test %>%
add_rownames() %>%
pivot_longer(-rowname) %>%
group_by(rowname) %>%
summarise(failed_incl = paste(name[value == 0 & name %in% c("A", "B", "C")], collapse = ", "),
failed_excl = paste(name[value == 1 & name %in% c("D", "E")], collapse = ", ")) %>%
select(-rowname)
bind_cols(test, failed_df)
A B C D E failed_incl failed_excl
1 0 0 0 1 1 A, B, C D, E
2 0 0 1 0 0 A, B
3 1 0 1 0 1 B E
rowwise
和 c_across
可能有更优雅的方法。
我有一个关于患者是否符合研究标准的数据框,每一行是一个患者,每一列是一个标准。所以有些列是纳入标准,有些列是排除标准,我想输出不合格的原因。例如,
test <- data.frame(A = c(0, 0, 1),
B = c(0, 0, 0),
C = c(0, 1, 1),
D = c(1, 0, 0),
E = c(1, 0, 1))
其中 A、B、C 是包含标准,D、E 是排除标准,如果包含标准 == 0 或排除标准 == 1,我想输出列名(可能不止一个) .
预期输出为
output <- data.frame(A = c(0, 0, 1),
B = c(0, 0, 0),
C = c(0, 1, 1),
D = c(1, 0, 0),
E = c(1, 0, 1),
failed_incl = c("A, B, C", "A, B", "B"),
failed_excl = c("D, E", "", "E"))
有没有一种方法可以高效地做到这一点而不必写出所有可能的场景?实际数据框有更多的列。
有多种方式。一种选择是使用 apply
遍历行 (MARGIN = 1
),将逻辑向量 (x== 0
) 的 names
和 paste
放在一起
test$failed_incl <- apply(test[1:3], 1, function(x) toString(names(x)[x == 0]))
test$failed_excl <- apply(test[4:5], 1, function(x) toString(names(x)[x == 1]))
-输出
test
# A B C D E failed_incl failed_excl
#1 0 0 0 1 1 A, B, C D, E
#2 0 0 1 0 0 A, B
#3 1 0 1 0 1 B E
或使用tidyverse
library(dplyr)
test %>%
rowwise %>%
mutate(failed_incl = toString(names(.)[which(c_across(A:C) == 0)]),
failed_excl = toString(c('D', 'E')[which(c_across(D:E) == 1)])) %>%
ungroup
# A tibble: 3 x 7
# A B C D E failed_incl failed_excl
# <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
#1 0 0 0 1 1 A, B, C "D, E"
#2 0 0 1 0 0 A, B ""
#3 1 0 1 0 1 B "E"
这里有一个 tidyverse 方法,它旋转列名,然后根据 inclusion/exclusion 条件进行汇总:
failed_df <-
test %>%
add_rownames() %>%
pivot_longer(-rowname) %>%
group_by(rowname) %>%
summarise(failed_incl = paste(name[value == 0 & name %in% c("A", "B", "C")], collapse = ", "),
failed_excl = paste(name[value == 1 & name %in% c("D", "E")], collapse = ", ")) %>%
select(-rowname)
bind_cols(test, failed_df)
A B C D E failed_incl failed_excl
1 0 0 0 1 1 A, B, C D, E
2 0 0 1 0 0 A, B
3 1 0 1 0 1 B E
rowwise
和 c_across
可能有更优雅的方法。