Во вложенных данных (tibble, вложенный в именованный список), как я мог изменить новый столбец на определенном уровне глубины на основе существования вложенных значений

#r #nested #nested-lists #tibble

#r #вложенный #вложенных списков #tibble

Вопрос:

Когда у меня есть данные, содержащие вложенные списки внутри, я хочу изменить новые столбцы на определенном уровне, обусловленном значениями, существующими на более глубоких вложенных уровнях. В частности, вложенный объект представляет собой именованный список, и я хочу проверить имена этого списка, чтобы сделать вывод о том, существует ли информация в данных или нет.


РЕДАКТИРОВАТЬ — я заменил данные в моем примере


Хотя ответ @Ronak действительно ответил на мой вопрос с данными, указанными изначально, я понял, что допустил ошибку, и пример данных toy неверно отражает структуру моих данных. Ниже приведены данные, которые правильно отражают мою ситуацию.

 library(tibble)

df_correct <-
  structure(
  list(
    var_name = c("age", "classes"),
    title = c("What is your age?",
              "what classes have you taken?"),
    class_descriptions = list(
      NULL,
      list(
        History = "History of Art",
        Chemistry = "Organic Chemistry",
        other = "Other Classes"
      )
    )
  ),
  row.names = c(NA,-2L),
  class = c("tbl_df",
            "tbl", "data.frame")
)

## # A tibble: 2 x 3
##   var_name title                        class_descriptions
##   <chr>    <chr>                        <list>            
## 1 age      What is your age?            <NULL>            
## 2 classes  what classes have you taken? <named list [3]>  <--- this list is what I need to check against

df_correct %>%
  unnest_wider(class_descriptions)

## # A tibble: 2 x 5
##                                    based on whether
##                                    "History" exists
##                                           ↓
##   var_name title                        History        Chemistry         other        
##   <chr>    <chr>                        <chr>          <chr>             <chr>        
## 1 age      What is your age?            NA             NA                NA           
## 2 classes  what classes have you taken? History of Art Organic Chemistry Other Classes
 

Итак, учитывая df_correct , и не обязательно используя unnest_wider (это было просто для того, чтобы показать структуру вложенных данных), как я могу изменить новый столбец, df_correct чтобы учесть, появляется ли в нем «История» class_descriptions ?

Желаемый результат — обновлен

 # A tibble: 2 x 4
  var_name title                        class_descriptions has_taken_history
  <chr>    <chr>                        <list>             <lgl>            
1 age      What is your age?            <NULL>             NA               
2 classes  what classes have you taken? <named list [3]>   TRUE  
 

Подробнее о желаемом решении (а не о выходе)

Я надеюсь при публикации этого вопроса найти способ добавить еще один столбец df_correct для определения того, существует ли строка в именах именованного списка class_descriptions . Другими словами, я ищу решение, которое потребует только 2 входных данных:

  1. Что искать (в данном примере строка "History" )
  2. Где искать (в данном примере имена именованного списка class_descriptions , который вложен в df_correct ).

Если строка найдена, заполните TRUE новый столбец в df_correct , в противном случае заполните FALSE .

скриншот

Ответ №1:

Редактировать 2

 df_correct %>%
  mutate(has_taken_history = map_lgl(class_descriptions, 
                                     ~'History' %in% names(.x)))

# var_name title                        class_descriptions has_taken_history
#  <chr>    <chr>                        <list>             <lgl>            
#1 age      What is your age?            <NULL>             FALSE            
#2 classes  what classes have you taken? <named list [3]>   TRUE        
 

Редактировать 1

Для отредактированных данных вы можете сделать :

 library(tidyverse)

df_correct %>%
  mutate(class_descriptions1 = class_descriptions) %>%
  unnest_wider(class_descriptions) %>%
  mutate(across(History:other, ~ifelse(is.na(.), NA, TRUE))) %>%
  dplyr::select(var_name, title, class_descriptions = class_descriptions1, has_taken_history = History)

# var_name title                        class_descriptions has_taken_history
#  <chr>    <chr>                        <list>             <lgl>            
#1 age      What is your age?            <NULL>             NA               
#2 classes  what classes have you taken? <named list [3]>   TRUE       
 

Вы можете сохранить только те объекты, которые вам нужны, из выходных данных.


Оригинальный ответ

Вы можете использовать map_lgl для возврата логического вектора :

 df %>% 
  unnest_wider(info) %>%
  mutate(has_taken_history = map_lgl(classes_taken, ~"History" %in% .x), 
         has_taken_chemistry = map_lgl(classes_taken, ~"Chemistry" %in% .x))

#  student_name location      year_born classes_taken has_taken_history has_taken_chemistry
#  <chr>        <chr>             <dbl> <list>        <lgl>             <lgl>              
#1 John         San Francisco      2000 <chr [4]>     TRUE              FALSE              
#2 Sarah        Miami              2002 <chr [4]>     TRUE              TRUE         
 

Более общим решением для всех субъектов было бы обращение к unnest субъектам и получение данных в широком формате.

 df %>% 
  unnest_wider(info) %>%
  unnest(classes_taken) %>%
  mutate(value = TRUE) %>%
  pivot_wider(names_from = classes_taken, values_from = value, values_fill = FALSE)
  
#  student_name location      year_born Astronomy Cosmology History Robotics Chemistry Biology Zoology
#  <chr>        <chr>             <dbl> <lgl>     <lgl>     <lgl>   <lgl>    <lgl>     <lgl>   <lgl>  
#1 John         San Francisco      2000 TRUE      TRUE      TRUE    TRUE     FALSE     FALSE   FALSE  
#2 Sarah        Miami              2002 FALSE     FALSE     TRUE    FALSE    TRUE      TRUE    TRUE