Условно заменить значения подмножества строк на имя столбца в R, используя только tidy

Я ищу способ условно заменить определенные значения в подмножестве столбцов, чтобы имя столбца оставалось в тидиверсе. См. Пример ниже:

wl <- data_frame(x=1:4,
  multi=c("Y","Y","Y","Y"),
  ABC=c("","Y","Y",""), 
  ABD=c("","","",""),
  ABE=c("Y","Y","","Y"))

# A tibble: 4 x 5
      x multi ABC   ABD   ABE  
  <int> <chr> <chr> <chr> <chr>
1     1 Y     ""    ""    Y    
2     2 Y     Y     ""    Y    
3     3 Y     Y     ""    ""   
4     4 Y     ""    ""    Y   

df <- wl %>% mutate_at(vars(matches("AB")),
         funs(replace(.,.=='Y',values = "column name")))
# A tibble: 4 x 5
      x multi ABC         ABD   ABE        
  <int> <chr> <chr>       <chr> <chr>      
1     1 Y     ""          ""    column name
2     2 Y     column name ""    column name
3     3 Y     column name ""    ""         
4     4 Y     ""          ""    column name

за исключением того, что это будет фактическое имя столбца, а не «имя столбца». Я использовал здесь два разных ответа, чтобы перейти как к изменению условных столбцов (именно так я попал в свой пример), так и к тому, как заменить определенные значения именем столбца (не используется в моем текущем примере, но ответ - здесь) .

Я могу объединить два ответа, чтобы заставить его работать:

w <- which(df= = "column name",arr.ind=TRUE)
df[w] <- names(df)[w[,"col"]]                 
# A tibble: 4 x 5
      x multi ABC   ABD   ABE  
  <int> <chr> <chr> <chr> <chr>
1     1 Y     ""    ""    ABE  
2     2 Y     ABC   ""    ABE  
3     3 Y     ABC   ""    ""   
4     4 Y     ""    ""    ABE 

Я подтверждаю, что описанный выше процесс полностью функционален, но из чистого любопытства есть ли способ сделать это без второго фрагмента кода? Есть ли какая-то функция, которую я могу подключить к части values= шага replace(.,.=='Y',values = "column name"), которая может захватывать имя столбца и выполнять весь этот процесс в рамках одной функции mutate_at?

Вы можете оставаться в тидиверсе и gather, затем mutate, затем spread, например wl %>% gather(ColName,Result, matches("AB")) %>% mutate(Result = if_else(Result = = "Y", ColName, Result)) %>% spread(ColName, Result).

Kerry Jackson 16.08.2018 21:14

@KerryJackson ах, очень умно и так просто ... Мне это нравится!

c.custer 16.08.2018 22:06
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
1 110
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вот вариант с imap

library(purrr)
AB_cols <- grep("^AB", names(wl)) # find positions of columns that start with "AB"
wl[AB_cols] <- imap(.x = wl[AB_cols], .f = ~replace(.x, .x == "Y", .y))
wl
# A tibble: 4 x 5
#      x multi ABC   ABD   ABE  
#  <int> <chr> <chr> <chr> <chr>
#1     1 Y     ""    ""    ABE  
#2     2 Y     ABC   ""    ABE  
#3     3 Y     ABC   ""    ""   
#4     4 Y     ""    ""    ABE 

Странно, что в вашем ответе он показывает, что ваш код заменяет несколько столбцов (чего я не хочу), но когда я запускаю его в моем R, он создает мою цель (заменяет только столбцы AB).

c.custer 16.08.2018 21:51

Мне нужно, чтобы он работал с start_with («AB») или аналогично ему, потому что мой реальный фрейм данных намного больше, чем в моем примере, и я не хочу всегда вручную подсчитывать номера индексов столбцов. Тем не менее, это полезная функция для изучения! Спасибо

c.custer 16.08.2018 21:53

@ c.custer Отредактировал мой ответ относительно вашего второго комментария. Но что вы имеете в виду, говоря «ваш код заменяет несколько столбцов»?

markus 16.08.2018 21:57

посмотрите на свой выходной тиббл. Все буквы «Y» были заменены на «multi», что является его столбцом. Это странно, потому что когда я запускал ваш код, он этого не делал.

c.custer 16.08.2018 22:00
Ответ принят как подходящий

Вы можете сделать небольшой выбор в своей функции mutate_at, чтобы получить имя столбца, затем ifelse (или любую другую логическую структуру, которую вы можете захотеть), чтобы заменить определенные значения.

library(tidyverse)

wl %>%
  mutate_at(vars(starts_with("AB")), function(x) {
    x_var <- rlang::enquo(x)
    ifelse(x == "Y", rlang::quo_name(x_var), x)
  })
#> # A tibble: 4 x 5
#>       x multi ABC   ABD   ABE  
#>   <int> <chr> <chr> <chr> <chr>
#> 1     1 Y     ""    ""    ABE  
#> 2     2 Y     ABC   ""    ABE  
#> 3     3 Y     ABC   ""    ""   
#> 4     4 Y     ""    ""    ABE

Создано 16.08.2018 пользователем пакет REPEX (v0.2.0).

Отлично, работает как шарм и хранит его внутри mutate_at

c.custer 16.08.2018 22:11

С tidy verse

library(dplyr)
wl %>% 
  mutate_at(vars(starts_with("AB")),
     funs(c("", deparse(substitute(.)))[(.= = "Y" & !is.na(.)) + 1]))
# A tibble: 4 x 5
#     x multi ABC   ABD   ABE  
#  <int> <chr> <chr> <chr> <chr>
#1     1 Y     ""    ""    ABE  
#2     2 Y     ABC   ""    ABE  
#3     3 Y     ABC   ""    ""   
#4     4 Y     ""    ""    ABE  

Использование base R

nm1 <- grep("^AB", names(wl))
i1 <- wl[,(nm1)] == "Y" & !is.na(wl[,(nm1)])
wl[,(nm1)][i1] <- names(wl)[(nm1)][col(wl[,(nm1)])][i1]
wl
# A tibble: 4 x 5
#      x multi ABC   ABD   ABE  
#  <int> <chr> <chr> <chr> <chr>
#1     1 Y     ""    ""    ABE  
#2     2 Y     ABC   ""    ABE  
#3     3 Y     ABC   ""    ""   
#4     4 Y     ""    ""    ABE  

Или мы можем сделать это быстрее, назначив на место с set из data.table

library(data.table)
setDT(wl)
for(j in nm1) set(wl, i=which(wl[[j]] == "Y"), j=j, names(wl)[j])
wl
#   x multi ABC ABD ABE
#1: 1     Y         ABE
#2: 2     Y ABC     ABE
#3: 3     Y ABC        
#4: 4     Y         ABE

Спасибо за предложение! Но мне нужно, чтобы он работал с start_with («AB») или аналогично ему, потому что мой реальный фрейм данных намного больше, чем в моем примере, и я не хочу, чтобы всегда вручную подсчитывал номера индексов столбцов.

c.custer 16.08.2018 21:54

@ c.custer. Ладно, поменял на более динамичный

akrun 16.08.2018 21:55

Отлично, спасибо! И спасибо за предоставление нескольких подходов. Всегда хорошо иметь больше инструментов

c.custer 16.08.2018 22:23

Ваш пример tidyverse работает, но я, честно говоря, не понимаю, что он делает? Где / как записывается имя столбца?

c.custer 16.08.2018 22:29

@ c.custer Это шаг deparse(substitute, который записывает имя перед оценкой

akrun 16.08.2018 22:31

Вы можете использовать replace_na:

wl%>%
   mutate_at(vars(starts_with('AB')),~`is.na<-`(.x,.x=='Y'))%>%
   replace_na(set_names(as.list(names(.)),names(.)))
# A tibble: 4 x 5
  x     multi ABC   ABD   ABE  
  <chr> <chr> <chr> <chr> <chr>
1 1     Y     ""    ""    ABE  
2 2     Y     ABC   ""    ABE  
3 3     Y     ABC   ""    ""   
4 4     Y     ""    ""    ABE  

Еще один отличный ответ! Я думаю, что меня беспокоит только то, что мои настоящие данные могут считываться в NA, а не в фактических пустых символах (моя вина, что я не показываю это в примере). Хотя я полагаю, что просто дважды использую ваш код, чтобы заменить фактические NA, и тогда Y будет работать так же хорошо. Спасибо!

c.custer 16.08.2018 22:10

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