Я ищу способ условно заменить определенные значения в подмножестве столбцов, чтобы имя столбца оставалось в тидиверсе. См. Пример ниже:
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?
@KerryJackson ах, очень умно и так просто ... Мне это нравится!





Вот вариант с 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).
Мне нужно, чтобы он работал с start_with («AB») или аналогично ему, потому что мой реальный фрейм данных намного больше, чем в моем примере, и я не хочу всегда вручную подсчитывать номера индексов столбцов. Тем не менее, это полезная функция для изучения! Спасибо
@ c.custer Отредактировал мой ответ относительно вашего второго комментария. Но что вы имеете в виду, говоря «ваш код заменяет несколько столбцов»?
посмотрите на свой выходной тиббл. Все буквы «Y» были заменены на «multi», что является его столбцом. Это странно, потому что когда я запускал ваш код, он этого не делал.
Вы можете сделать небольшой выбор в своей функции 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
С 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. Ладно, поменял на более динамичный
Отлично, спасибо! И спасибо за предоставление нескольких подходов. Всегда хорошо иметь больше инструментов
Ваш пример tidyverse работает, но я, честно говоря, не понимаю, что он делает? Где / как записывается имя столбца?
@ c.custer Это шаг deparse(substitute, который записывает имя перед оценкой
Вы можете использовать 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 будет работать так же хорошо. Спасибо!
Вы можете оставаться в тидиверсе и
gather, затемmutate, затемspread, напримерwl %>% gather(ColName,Result, matches("AB")) %>% mutate(Result = if_else(Result = = "Y", ColName, Result)) %>% spread(ColName, Result).