Использование case_when () в mutate_at () для перекодирования строк выбранных столбцов с разными типами с помощью NA - PullRequest
2 голосов
/ 28 февраля 2020

Учитывая данные:

df <- structure(list(cola = structure(c(5L, 9L, 6L, 2L, 7L, 10L, 3L, 
8L, 1L, 4L), .Label = c("a", "b", "d", "g", "q", "r", "t", "w", 
"x", "z"), class = "factor"), colb = c(156L, 8L, 6L, 100L, 49L, 
31L, 189L, 77L, 154L, 171L), colc = c(0.207140279468149, 0.51990159181878, 
0.402017514919862, 0.382948065642267, 0.488511856179684, 0.263168515404686, 
0.38591041485779, 0.774066215148196, 0.763264901703224, 0.474355421960354
), cold = structure(c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L), .Label = c("a", 
"b"), class = "factor")), class = "data.frame", row.names = c(NA, 
-10L))

df
#    cola colb      colc cold
# 1     q  156 0.2071403    a
# 2     x    8 0.5199016    b
# 3     r    6 0.4020175    a
# 4     b  100 0.3829481    b
# 5     t   49 0.4885119    a
# 6     z   31 0.2631685    b
# 7     d  189 0.3859104    a
# 8     w   77 0.7740662    b
# 9     a  154 0.7632649    a
# 10    g  171 0.4743554    b

Если значение в colc в конкретной строке равно >= 0.5, я хотел бы заменить содержимое всех других ячеек в этой строке на NA, за исключением содержимого cold для этой строки (которую я хотел бы сохранить как есть).

Я попытался сделать это с помощью dplyr::mutate_at() и base::ifelse(), и она отлично работает:

df %>% mutate_at(vars(-c(cold)), funs(ifelse(colc >= 0.5, NA, .)))

#    cola colb      colc cold
# 1     5  156 0.2071403    a
# 2    NA   NA        NA    b
# 3     6    6 0.4020175    a
# 4     2  100 0.3829481    b
# 5     7   49 0.4885119    a
# 6    10   31 0.2631685    b
# 7     3  189 0.3859104    a
# 8    NA   NA        NA    b
# 9    NA   NA        NA    a
# 10    4  171 0.4743554    b

Но я хотел бы сделать это с dplyr::case_when(), поскольку мне может потребоваться выполнить более одного условия замены (например, заменить на "foo", если colc < 0.5 & colc >= 0.3. Но case_when(), похоже, не игра приятно:

df %>% mutate_at(vars(-c(cold)), funs(case_when(colc >= 0.5 ~ NA, TRUE ~ .)))

Ошибка: должен быть логическим вектором, а не фактором-фактором

Почему это происходит и что я могу сделать, чтобы это исправить? I Предположим, это потому, что я пытаюсь преобразовать несколько столбцов с разными типами данных в NA. Я пытался найти решение в Интернете, но не смог найти его.

Редактировать: в спецификации c я бы хотел сохранить типы данных различных столбцов такими, какие они есть.

Ответы [ 2 ]

3 голосов
/ 28 февраля 2020
library(dplyr)

df %>%
  mutate_at(vars(-c(cold)), ~ case_when(colc >= 0.5 ~ `is.na<-`(., TRUE), TRUE ~ .))

#    cola colb      colc cold
# 1     q  156 0.2071403    a
# 2  <NA>   NA        NA    b
# 3     r    6 0.4020175    a
# 4     b  100 0.3829481    b
# 5     t   49 0.4885119    a
# 6     z   31 0.2631685    b
# 7     d  189 0.3859104    a
# 8  <NA>   NA        NA    b
# 9  <NA>   NA        NA    a
# 10    g  171 0.4743554    b

Описание

Когда вы используете case_when для назначения NA, вам необходимо указать тип NA, то есть NA_integer_, NA_real_ NA_complex_ и NA_character_. Однако mutate_at преобразует несколько столбцов одновременно, и эти столбцы имеют разные типы, поэтому вы не можете применить один оператор ко всем столбцам. В идеале, может существовать что-то вроде NA_guess для идентификации типа, но я пока не нахожу это. Этот метод немного хитрый. Я использую is.na() для преобразования входного вектора в NA, и эти NA будут того же типа, что и входной вектор. Например:

x <- 1:5
is.na(x) <- T ; x
# [1] NA NA NA NA NA
class(x)
# [1] "integer"

y <- letters[1:5]
is.na(y) <- T ; y
# [1] NA NA NA NA NA
class(y)
# [1] "character"
3 голосов
/ 28 февраля 2020

Работа вокруг похожа на @NelsonGon:

library(dplyr)

df %>%
        mutate_all(as.character) %>% 
        mutate_at(vars(-c(cold)), 
                  ~case_when(colc >= 0.5 ~ NA_character_, # ifelse(is.numeric(.), NA_real_, NA_character_), 
                             TRUE ~ .
                  )
        ) %>% 
        mutate(colb = as.numeric(colb),
               colc = as.numeric(colc)
        )

#>    cola colb      colc cold
#> 1     q  156 0.2071403    a
#> 2  <NA> <NA>        NA    b
#> 3     r    6 0.4020175    a
#> 4     b  100 0.3829481    b
#> 5     t   49 0.4885119    a
#> 6     z   31 0.2631685    b
#> 7     d  189 0.3859104    a
#> 8  <NA> <NA>        NA    b
#> 9  <NA> <NA>        NA    a
#> 10    g  171 0.4743554    b
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...