Перекодировать фрейм данных на основе столбца индекса

У меня есть следующий фрейм данных df:

 Index col_a col_b col_c col_d
1     4     c     v     g     j
2     1     x  <NA>     z     s
3  1, 3     k     j     n     y
4     2     q     t     o     i
5  2, 3     y     m     w     r
6     2     d     u     x     a
7  3, 4     n     y     k     g
8     4     h     d  <NA>     u
9     1     s     x     j     m
df <- structure(list(Index = c("4", "1", "1, 3", "2", "2, 3", "2", 
"3, 4", "4", "1"), col_a = c("c", "x", "k", "q", "y", "d", "n", 
"h", "s"), col_b = c("v", NA, "j", "t", "m", "u", "y", "d", "x"
), col_c = c("g", "z", "n", "o", "w", "x", "k", NA, "j"), col_d = c("j", 
"s", "y", "i", "r", "a", "g", "u", "m")), class = "data.frame", row.names = c(NA, 
-9L))

Я хочу перекодировать/обновить значения в df на «Да»/«Нет» на основе столбца Index, где 1 = col_a, 2 = col_b и так далее.

Это мой желаемый результат:

  Index col_a col_b col_c col_d
1     4    No    No    No   Yes
2     1   Yes    No    No    No
3  1, 3   Yes    No   Yes    No
4     2    No   Yes    No    No
5  2, 3    No   Yes   Yes    No
6     2    No   Yes    No    No
7  3, 4    No    No   Yes   Yes
8     4    No    No    No   Yes
9     1   Yes    No    No    No

В настоящее время я использую подход lapply для решения проблемы, но мне интересно, есть ли более простое решение всего в одной или двух строках кода.

do.call(rbind, lapply(1:nrow(df), \(x) {
  vec <- as.integer(unlist(strsplit(df[x, 1], ","))) + 1
  df[x, vec] <- "Yes"
  df[x, -c(1, vec)] <- "No"
  df[x, ]
}))
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
68
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вариант base R состоит в том, чтобы использовать row/column индексацию, которая должна выполняться быстрее для присваивания, чем при циклическом цикле по строкам.

m1 <- cbind(rep(seq_len(nrow(df)), nchar(gsub("\\D+", "", df$Index))), 
    scan(text = df$Index, what = numeric(), sep = ","))
df[-1][m1] <- "Yes"
df[-1][df[-1] != "Yes"|is.na(df[-1])] <- "No"

-выход

> df
  Index col_a col_b col_c col_d
1     4    No    No    No   Yes
2     1   Yes    No    No    No
3  1, 3   Yes    No   Yes    No
4     2    No   Yes    No    No
5  2, 3    No   Yes   Yes    No
6     2    No   Yes    No    No
7  3, 4    No    No   Yes   Yes
8     4    No    No    No   Yes
9     1   Yes    No    No    No

Или еще такой вариант

i1 <- Reduce(`|`, lapply(read.csv(text = df$Index, 
    header = FALSE),\(x) col(df[-1]) == x))
df[-1] <- c("No", "Yes")[1+(i1 & !is.na(i1))]

-выход

> df
  Index col_a col_b col_c col_d
1     4    No    No    No   Yes
2     1   Yes    No    No    No
3  1, 3   Yes    No   Yes    No
4     2    No   Yes    No    No
5  2, 3    No   Yes   Yes    No
6     2    No   Yes    No    No
7  3, 4    No    No   Yes   Yes
8     4    No    No    No   Yes
9     1   Yes    No    No    No

Или с tidyverse

library(dplyr)
library(stringr)
df %>%
  mutate(across(starts_with("col_"),
   ~ case_when(str_detect(Index, as.character( match(cur_column(), 
      names(df))-1)) ~ "Yes", TRUE ~ "No")))

-выход

  Index col_a col_b col_c col_d
1     4    No    No    No   Yes
2     1   Yes    No    No    No
3  1, 3   Yes    No   Yes    No
4     2    No   Yes    No    No
5  2, 3    No   Yes   Yes    No
6     2    No   Yes    No    No
7  3, 4    No    No   Yes   Yes
8     4    No    No    No   Yes
9     1   Yes    No    No    No

То, что у вас уже есть, кажется довольно хорошим. Мы могли бы внести несколько незначительных улучшений, как показано ниже:

Index <- strsplit(df[[1]], ",")
do.call("rbind", lapply(1:nrow(df), function(i) {
  dfi <- df[i, ]
  dfi[-1] <- "No"
  replace(dfi, as.integer(Index[[i]]) + 1L, "Yes")
}))

Другие вопросы по теме