连接一列中的列名,条件是使用 mutate、across 和 case_when
Concatenate column names in one column conditional on using mutate, across and case_when
我愿意:
- 使用
across
和 case_when
检查 A1-A3 列是否 == 1
- 连接 A1-A3 == 1 和
的列的列名
- 用连接的列名改变一个新列
我的数据框:
df <- tribble(
~ID, ~A1, ~A2, ~A3,
1, 0, 1, 1,
2, 0, 1, 1,
3, 1, 1, 1,
4, 1, 0, 1,
5, 0, 1, 0)
期望的输出:
# A tibble: 5 x 5
ID A1 A2 A3 New_Col
<dbl> <dbl> <dbl> <dbl> <chr>
1 1 0 1 1 A2 A3
2 2 0 1 1 A2 A3
3 3 1 1 1 A1 A2 A3
4 4 1 0 1 A1 A3
5 5 0 1 0 A2
到目前为止我已经尝试过:
df %>%
rowwise() %>%
mutate(New_Col = across(A1:A3, ~ case_when(. == 1 ~ paste0("colnames(.)", collapse = " "))))
不工作输出:
ID A1 A2 A3 New_Col$A1 $A2 $A3
<dbl> <dbl> <dbl> <dbl> <chr> <chr> <chr>
1 1 0 1 1 NA colnames(.) colnames(.)
2 2 0 1 1 NA colnames(.) colnames(.)
3 3 1 1 1 colnames(.) colnames(.) colnames(.)
4 4 1 0 1 colnames(.) NA colnames(.)
5 5 0 1 0 NA colnames(.) NA
我想学什么:
- 是否可以使用
across
检查多列的条件
- 如果是,如何查看
case_when
~ 之后的部分以获得特定的 colnames
- 如何在使用
mutate
、across
和 case_when
后只得到一列,而不是这里的 3 列。
我以为我已经可以掌握这个任务了,但不知怎么的我把它弄丢了...
要将 across
与 case_when
一起使用,您可以执行 -
library(dplyr)
library(tidyr)
df %>%
mutate(across(A1:A3, ~case_when(. == 1 ~ cur_column()), .names = 'new_{col}')) %>%
unite(New_Col, starts_with('new'), na.rm = TRUE, sep = ' ')
# ID A1 A2 A3 New_Col
# <dbl> <dbl> <dbl> <dbl> <chr>
#1 1 0 1 1 A2 A3
#2 2 0 1 1 A2 A3
#3 3 1 1 1 A1 A2 A3
#4 4 1 0 1 A1 A3
#5 5 0 1 0 A2
across
创建 3 个名为 new_A1
、new_A2
和 new_A3
的新列,如果值为 1 则使用列名,否则为 NA
。使用 unite
我们将 3 列合并为一列 New_col
.
我们也可以使用 rowwise
和 c_across
-
df %>%
rowwise() %>%
mutate(New_Col = paste0(names(.[-1])[c_across(A1:A3) == 1], collapse = ' '))
没有rowwise
/across
你也可以使用cur_data()
获得相同的
df %>% group_by(ID) %>%
mutate(new_col = paste0(names(df[-1])[as.logical(cur_data())], collapse = ' '))
# A tibble: 5 x 5
# Groups: ID [5]
ID A1 A2 A3 new_col
<dbl> <dbl> <dbl> <dbl> <chr>
1 1 0 1 1 A2 A3
2 2 0 1 1 A2 A3
3 3 1 1 1 A1 A2 A3
4 4 1 0 1 A1 A3
5 5 0 1 0 A2
a .
而不是 df
inside mutate 也会做
df %>% group_by(ID) %>%
mutate(new_col = paste0(names(.[-1])[as.logical(cur_data())], collapse = ' '))
也涉及 purrr
的一个选项可能是:
df %>%
mutate(New_Col = pmap_chr(across(-ID),
~ paste(names(c(...))[which(c(...) == 1)], collapse = " ")))
ID A1 A2 A3 New_Col
<dbl> <dbl> <dbl> <dbl> <chr>
1 1 0 1 1 A2 A3
2 2 0 1 1 A2 A3
3 3 1 1 1 A1 A2 A3
4 4 1 0 1 A1 A3
5 5 0 1 0 A2
使用base R
df$New_Col <- apply(df[-1], 1, \(x) paste(names(x)[as.logical(x)], collapse=' '))
df$New_Col
#[1] "A2 A3" "A2 A3" "A1 A2 A3" "A1 A3" "A2"
或使用tidyverse
library(dplyr)
library(purrr)
library(stringr)
df %>%
mutate(New_Col = across(A1:A3, ~ c('', cur_column())[. + 1] ) %>%
invoke(str_c, .))
我愿意:
- 使用
across
和case_when
检查 A1-A3 列是否 == 1 - 连接 A1-A3 == 1 和 的列的列名
- 用连接的列名改变一个新列
我的数据框:
df <- tribble(
~ID, ~A1, ~A2, ~A3,
1, 0, 1, 1,
2, 0, 1, 1,
3, 1, 1, 1,
4, 1, 0, 1,
5, 0, 1, 0)
期望的输出:
# A tibble: 5 x 5
ID A1 A2 A3 New_Col
<dbl> <dbl> <dbl> <dbl> <chr>
1 1 0 1 1 A2 A3
2 2 0 1 1 A2 A3
3 3 1 1 1 A1 A2 A3
4 4 1 0 1 A1 A3
5 5 0 1 0 A2
到目前为止我已经尝试过:
df %>%
rowwise() %>%
mutate(New_Col = across(A1:A3, ~ case_when(. == 1 ~ paste0("colnames(.)", collapse = " "))))
不工作输出:
ID A1 A2 A3 New_Col$A1 $A2 $A3
<dbl> <dbl> <dbl> <dbl> <chr> <chr> <chr>
1 1 0 1 1 NA colnames(.) colnames(.)
2 2 0 1 1 NA colnames(.) colnames(.)
3 3 1 1 1 colnames(.) colnames(.) colnames(.)
4 4 1 0 1 colnames(.) NA colnames(.)
5 5 0 1 0 NA colnames(.) NA
我想学什么:
- 是否可以使用
across
检查多列的条件 - 如果是,如何查看
case_when
~ 之后的部分以获得特定的 colnames - 如何在使用
mutate
、across
和case_when
后只得到一列,而不是这里的 3 列。
我以为我已经可以掌握这个任务了,但不知怎么的我把它弄丢了...
要将 across
与 case_when
一起使用,您可以执行 -
library(dplyr)
library(tidyr)
df %>%
mutate(across(A1:A3, ~case_when(. == 1 ~ cur_column()), .names = 'new_{col}')) %>%
unite(New_Col, starts_with('new'), na.rm = TRUE, sep = ' ')
# ID A1 A2 A3 New_Col
# <dbl> <dbl> <dbl> <dbl> <chr>
#1 1 0 1 1 A2 A3
#2 2 0 1 1 A2 A3
#3 3 1 1 1 A1 A2 A3
#4 4 1 0 1 A1 A3
#5 5 0 1 0 A2
across
创建 3 个名为 new_A1
、new_A2
和 new_A3
的新列,如果值为 1 则使用列名,否则为 NA
。使用 unite
我们将 3 列合并为一列 New_col
.
我们也可以使用 rowwise
和 c_across
-
df %>%
rowwise() %>%
mutate(New_Col = paste0(names(.[-1])[c_across(A1:A3) == 1], collapse = ' '))
没有rowwise
/across
你也可以使用cur_data()
df %>% group_by(ID) %>%
mutate(new_col = paste0(names(df[-1])[as.logical(cur_data())], collapse = ' '))
# A tibble: 5 x 5
# Groups: ID [5]
ID A1 A2 A3 new_col
<dbl> <dbl> <dbl> <dbl> <chr>
1 1 0 1 1 A2 A3
2 2 0 1 1 A2 A3
3 3 1 1 1 A1 A2 A3
4 4 1 0 1 A1 A3
5 5 0 1 0 A2
a .
而不是 df
inside mutate 也会做
df %>% group_by(ID) %>%
mutate(new_col = paste0(names(.[-1])[as.logical(cur_data())], collapse = ' '))
也涉及 purrr
的一个选项可能是:
df %>%
mutate(New_Col = pmap_chr(across(-ID),
~ paste(names(c(...))[which(c(...) == 1)], collapse = " ")))
ID A1 A2 A3 New_Col
<dbl> <dbl> <dbl> <dbl> <chr>
1 1 0 1 1 A2 A3
2 2 0 1 1 A2 A3
3 3 1 1 1 A1 A2 A3
4 4 1 0 1 A1 A3
5 5 0 1 0 A2
使用base R
df$New_Col <- apply(df[-1], 1, \(x) paste(names(x)[as.logical(x)], collapse=' '))
df$New_Col
#[1] "A2 A3" "A2 A3" "A1 A2 A3" "A1 A3" "A2"
或使用tidyverse
library(dplyr)
library(purrr)
library(stringr)
df %>%
mutate(New_Col = across(A1:A3, ~ c('', cur_column())[. + 1] ) %>%
invoke(str_c, .))