`dplyr::if_else()` по сравнению с базовым R `ifelse()` - почему ошибка rbindlist?

Этот блок кода ниже, использующий dplyr::if_else(), работает без проблем и создает показанную гибкую таблицу.

library(tidyverse)
library(flextable)

# utilizing dplyr if_else
df1 <- tibble(col1 = c(5, 2), col2 = c(6, 4)) %>% 
  mutate(col3 = if_else(apply(.[, 1:2], 1, sum) > 10 & .[, 2] > 5, 
                        "True",
                        "False"))
df1 %>% flextable() %>% theme_zebra()

таблица

Сначала я попробовал это с базой R ifelse() и получил ошибку, показанную ниже. Ошибка, кажется, не имеет никакого смысла. Кто-нибудь может объяснить? В моем фрейме данных нет около 15 столбцов.

# utilizing base R ifelse
df2 <- tibble(col1 = c(5, 2), col2 = c(6, 4)) %>% 
  mutate(col3 = ifelse(apply(.[, 1:2], 1, sum) > 10 & .[, 2] > 5, 
                        "True",
                        "False"))
df2 %>% flextable() %>% theme_zebra()

# Error in rbindlist(x$content$data) : 
  # Item 5 has 15 columns, inconsistent with item 1 which has 14 columns. 
  # To fill missing columns use fill=TRUE.

person Display name    schedule 25.04.2019    source источник
comment
Что произойдет, если вы запустите базу ifelse с fill=TRUE?   -  person TheSciGuy    schedule 25.04.2019
comment
Если я добавлю , fill = TRUE после "False", я все равно получу ту же ошибку. Даже если это сработало, мне любопытно, что происходит.   -  person Display name    schedule 25.04.2019
comment
Вы проверили, не была ли одна из ваших переменных или функций замаскирована/перезаписана? Попробуйте очистить глобальную среду, у меня код работает нормально   -  person    schedule 25.04.2019
comment
Взгляните на str(df2). Вы можете видеть, что df2$col3 — это matrix 2x1, тогда как df1$col3 — это вектор chr.   -  person Maurits Evers    schedule 25.04.2019
comment
Кроме того, ваш синтаксис dplyr кажется несколько необычным. Почему бы не сделать ... + mutate(col3 = if_else(col1 + col2 > 10 & col2 < 5, "True", "False"))? Здесь нет необходимости в вызове apply с MARGIN = 1, поскольку операции уже векторизованы по строкам.   -  person Maurits Evers    schedule 25.04.2019
comment
Не использовал этот подход, потому что имена моих столбцов в импортированных данных часто меняются, хотя их относительные положения остаются прежними. Я расскажу об этом в своем следующем вопросе о стеке, который скоро появится.   -  person Display name    schedule 25.04.2019
comment
@JasonHunter Я бы все же посоветовал не использовать apply в подходе dplyr/tidyr (как вы узнали, решения на основе apply могут привести к неожиданные результаты при работе с data.frames). Если у вас есть несколько (и/или разное количество) столбцов, более tidyverse-каноническим подходом будет изменение формы с широкой на длинную, а затем работа с вашими длинными данными перед изменением формы обратно на широкую. С нетерпением жду вашего следующего вопроса SO, чтобы расширить ;-)   -  person Maurits Evers    schedule 26.04.2019


Ответы (2)


Не flextable эксперт, но после разбора вашей проблемы я наблюдаю

df <- tibble::tibble(col1 = c(5, 2), col2 = c(6, 4))

ifelse(apply(df[, 1:2], 1, sum) > 10 & df[, 2] > 5, "True", "False")
#     col2   
#[1,] "True" 
#[2,] "False"

которая представляет собой матрицу 2 X 1 и

dplyr::if_else(apply(df[, 1:2], 1, sum) > 10 & df[, 2] > 5, "True", "False")
#[1] "True"  "False"

является вектором символов. Итак, если вы сделаете

df2 <- tibble(col1 = c(5, 2), col2 = c(6, 4)) %>% 
       mutate(col3 = as.character(ifelse(apply(.[, 1:2], 1, sum) > 10 & .[, 2] > 5, 
                   "True", "False")))

он работает так, как ожидалось.

person Ronak Shah    schedule 25.04.2019
comment
Почему ifelse() создает матрицу, хотя я этого не прошу? Это просто дизайнерское решение, которое функция dplyr::if_else() предпочла не принимать по каким-то предположительно веским причинам. - person Display name; 25.04.2019
comment
@JasonHunter не совсем уверен, но может быть что-то связанное с тем, что if_else имеет строгую проверку типов. - person Ronak Shah; 25.04.2019

Как продемонстрировал @ronak-shah, ваше ifelse создает матрицу, что не нравится flextable ;)

Вам не нужно форматировать данные перед использованием flextable. Например, я бы использовал colformat_lgl там:

df2 <- tibble(col1 = c(5, 2), col2 = c(6, 4)) %>% 
  mutate( col3 = rowSums(.) > 10 & col2 > 5 )

flextable(df2) %>% 
  colformat_lgl("col3", true = "True", false = "False")
person David Gohel    schedule 25.04.2019