примените функцию к столбцам, используя имена столбцов внутри функции

#r #dplyr #across

Вопрос:

Я пытаюсь перебрать более 100 столбцов, чтобы определить, соответствует ли переменная a в отдельном столбце имени столбца. Я подумал, что, возможно, функция across сможет это сделать, но не могу понять, как использовать мутацию в каждом столбце. См.Пример ниже.

 tst=structure(list(type = c("DOG", "DOG", "DOG", "CAT", "CAT", "CAT", 
"MOUSE", "MOUSE", "MOUSE"), CAT = c(NA_character_, NA_character_, 
NA_character_, NA_character_, NA_character_, NA_character_, NA_character_, 
NA_character_, NA_character_), DOG = c(NA_character_, NA_character_, 
NA_character_, NA_character_, NA_character_, NA_character_, NA_character_, 
NA_character_, NA_character_), MOUSE = c(NA_character_, NA_character_, 
NA_character_, NA_character_, NA_character_, NA_character_, NA_character_, 
NA_character_, NA_character_), id = 1:9), row.names = c(NA, -9L
), class = c("tbl_df", "tbl", "data.frame"))
 

В настоящее время моя таблица имеет следующую структуру.

    type  CAT   DOG   MOUSE    id
  <chr> <chr> <chr> <chr> <int>
1 DOG   NA    NA    NA        1
2 DOG   NA    NA    NA        2
3 DOG   NA    NA    NA        3
4 CAT   NA    NA    NA        4
5 CAT   NA    NA    NA        5
6 CAT   NA    NA    NA        6
7 MOUSE NA    NA    NA        7
8 MOUSE NA    NA    NA        8
9 MOUSE NA    NA    NA        9

 

Я бы хотел, чтобы конечный результат выглядел так:

    type  CAT   DOG   MOUSE    id
  <chr> <chr> <chr> <chr> <int>
1 DOG   NA    TRUE  NA        1
2 DOG   NA    TRUE  NA        2
3 DOG   NA    TRUE  NA        3
4 CAT   TRUE  NA    NA        4
5 CAT   TRUE  NA    NA        5
6 CAT   TRUE  NA    NA        6
7 MOUSE NA    NA    TRUE      7
8 MOUSE NA    NA    TRUE      8
9 MOUSE NA    NA    TRUE      9 

This works but it is not sufficient for 100 columns.

tst<-tst%>%mutate(CAT=ifelse(type==names(tst[2]),'TRUE',NA))
tst<-tst%>%mutate(DOG=ifelse(type==names(tst[3]),'TRUE',NA))
tst<-tst%>%mutate(MOUSE=ifelse(type==names(tst[4]),'TRUE',NA))
 

Ответ №1:

Возможным решением является следующее (без dplyr )

 # initialise list
tmpList <- list()

# iterate over each row
for (i in 1:nrow(tst)) {
  
  tmpList[[i]] <- colnames(tst[-c(1,5)]) %in% tst$type[i]
  
}

# save as data frame
output <- as.data.frame(do.call(rbind, tmpList))
colnames(output) <- colnames(tst[-c(1,5)]) 

# cbind with data
output <- cbind(tst[,c(1,5)],output)
 

Что дает то, что вы ищете! Если и есть лучшее решение, то это не то, что легко приходит мне в голову.

Лучше всех!

Ответ №2:

dplyr Решение этой проблемы очень простое. Вы можете использовать across() с cur_column() , чтобы получить имя текущего столбца и указать его в своей формуле:

 tst %>% 
  mutate(across(CAT:MOUSE, ~if_else(type == cur_column(), 'TRUE', .x)))
 

Вы можете CAT:MOUSE заменить любую функцию аккуратного выбора, которая вам нужна, чтобы собрать более 100 столбцов.

Вот полный репрекс:

 library(tidyverse)

# I like tibbles because they print nicely, but this could just be a plain dataframe
tst <- tibble(
  type = c(
    "DOG", "DOG", "DOG", "CAT", "CAT", "CAT",
    "MOUSE", "MOUSE", "MOUSE"
  ),
  CAT = NA_character_,
  DOG = NA_character_,
  MOUSE = NA_character_,
  id = 1:9
)

# .x here could be NA_character_, if you don't want the value from the existing column
tst %>% 
  mutate(across(CAT:MOUSE, ~if_else(type == cur_column(), 'TRUE', .x)))
#> # A tibble: 9 x 5
#>   type  CAT   DOG   MOUSE    id
#>   <chr> <chr> <chr> <chr> <int>
#> 1 DOG   <NA>  TRUE  <NA>      1
#> 2 DOG   <NA>  TRUE  <NA>      2
#> 3 DOG   <NA>  TRUE  <NA>      3
#> 4 CAT   TRUE  <NA>  <NA>      4
#> 5 CAT   TRUE  <NA>  <NA>      5
#> 6 CAT   TRUE  <NA>  <NA>      6
#> 7 MOUSE <NA>  <NA>  TRUE      7
#> 8 MOUSE <NA>  <NA>  TRUE      8
#> 9 MOUSE <NA>  <NA>  TRUE      9
 

Создано 2021-04-23 пакетом reprex (v1.0.0)