Изменить NULL на NA в списке без преобразования

У меня есть список, который я превращаю в фрейм данных. Список возвращается из API и содержит несколько значений NULL. Есть вопросы по SO по этой теме здесь и здесь, но они либо имеют дело с кадрами данных или, в случае второй ссылки, OP было предложено сначала преобразовать в кадр данных. Я хочу сохранить структуру списка.

Я разбираю его следующим образом, вот некоторые примеры данных:

example <- list(
  list(
    ID = "1",
    Name = "Joe",
    Middle_name = "Alan",
    Surname = "Smith"
  ),
  list(
    ID = "2",
    Name = "Sarah",
    Middle_name = NULL,
    Surname = "Jones"
  ),
  list(
    ID = "3",
    Name = "Robert",
    Middle_name = "Myles",
    Surname = "McDonnell"
  )
)

N <- NA_character_

df <- tibble::tibble(
  id = purrr::map_chr(example, .null = N, "ID"),
  name = purrr::map_chr(example, .null = N, "Name"),
  middle = purrr::map_chr(example, .null = N, "Middle_name"),
  surname = purrr::map_chr(example, .null = N, "Surname")
)


> df
# A tibble: 3 x 4
     id   name middle   surname
  <chr>  <chr>  <chr>     <chr>
1     1    Joe   <NA>     Smith
2     2  Sarah   <NA>     Jones
3     3 Robert   <NA> McDonnell

Похоже, у этой проблемы есть некоторая история в репозитории, но когда я использую функции purrr например is_empty() или compact(), я либо получаю сообщение об ошибке, либо оно не работает.

Кто-нибудь знает, как я могу этого добиться, предпочтительно придерживаясь метода tibble и map_chr, который я использую выше?


person RobertMyles    schedule 23.06.2017    source источник
comment
Почему вы говорите, что я хочу сохранить структуру списка, когда вы действительно хотите превратить его в фрейм данных. Вы действительно хотите превратить его в фрейм данных, да?   -  person Spacedman    schedule 23.06.2017
comment
В конце концов, но я хотел бы сделать это, используя муррр в списке, как указано выше.   -  person RobertMyles    schedule 24.06.2017
comment
А как насчет map_df(transpose(example), ~map_chr(.,~ifelse(is.null(.),NA,.)))?   -  person HubertL    schedule 24.06.2017
comment
Это определенно удерживает его в рамках муррр и прекрасно работает (спасибо!), но сначала транспонирует его, поэтому я не смогу использовать описанный выше подход tibble. Тем не менее, лучший ответ.   -  person RobertMyles    schedule 24.06.2017
comment
Я только что обновился до разрабатываемой версии purrr, и ваш пример работает просто отлично, за исключением небольшой опечатки. В example вы используете Middle_name, но в map_chr вы ссылаетесь на Middle_Name.   -  person aosmith    schedule 24.06.2017
comment
@aosmith Ну, что ты знаешь!! Я знал, что есть решение. Не совсем тот ответ, которого я ожидал, но если вы напишете его как ответ, я с радостью его приму. Спасибо, работает отлично, только что проверил.   -  person RobertMyles    schedule 24.06.2017
comment
Выполнение этого с функциями N map_chr означает перебор всего списка N раз. Делая это поэлементно, как с lapply, и rbind выполняет итерацию по списку один раз. Быстрый тест производительности показал, что подход map_chr работает в десять раз медленнее. Это цена, которую вы платите за чистоту.   -  person Spacedman    schedule 24.06.2017
comment
@Spacedman спасибо :-)   -  person RobertMyles    schedule 24.06.2017
comment
@Spacedman Использование map_chr() N раз эквивалентно использованию vapply() N раз. Ничего особенного в этом нет. Только что протестированный с bind_rows() и flatten_chr() аккуратная версия на самом деле быстрее, чем предлагаемая базовая версия. Более того, мы подумывали о том, чтобы использовать для такого рода проблем подход, основанный на спецификации столбца. Это позволило бы readr API создавать фреймы данных из списков и могло бы быть удобно для разнородных списков списков.   -  person Lionel Henry    schedule 13.11.2017
comment
@lionel, спасибо за информацию. Я нахожу этот подход действительно полезным для работы с беспорядочными интернет-данными, плохо написанными API и т. д. Часто мне нужно какое-то время поработать со списком, прежде чем превратить все в фрейм данных.   -  person RobertMyles    schedule 13.11.2017


Ответы (1)


Ваш пример работает с разрабатываемой версией purrr.

Строки NULL создают проблемы для подходов, таких как использование dplyr::bind_rows, которые в противном случае работали бы для сворачивания списка списков в табличку. Обходной путь для удаления строки NULL состоит в том, чтобы перебрать и flatten каждый список. Цикл через map_df связывает строки и дает желаемый результат.

map_df(example, flatten)

# A tibble: 3 x 4
     ID   Name Middle_name   Surname
  <chr>  <chr>       <chr>     <chr>
1     1    Joe        Alan     Smith
2     2  Sarah        <NA>     Jones
3     3 Robert       Myles McDonnell
person aosmith    schedule 26.06.2017