Как вытащить пары данных из списка внутри фрейма данных (с tidyverse) - PullRequest
1 голос
/ 04 февраля 2020

У меня есть вывод json (из topydo), который имеет (после некоторых манипуляций) столбец, называемый тегами, где теги (если они присутствуют) являются парами данных в списке. Обычно это будет срок оплаты, иногда повторение «re c», а иногда и то и другое. Приведенный ниже воспроизводимый пример, который создает фрейм данных со столбцом 'tags', содержащим списки списков обязательных / повторных c пар.

Я хочу разделить эти списки (подобно pivot_wider или spread) но для элементов в списке, поэтому я хочу превратить этот элемент списка:

[[1]]
     [,1]  [,2]        
[1,] "rec" "+6m"       
[2,] "due" "2020-02-02"

в два столбца - re c и должное.

Это то, что «теги» Столбец выглядит следующим образом:

> todo.df$tags
[[1]]
     [,1]  [,2]        
[1,] "rec" "+6m"       
[2,] "due" "2020-02-02"

[[2]]
list()

[[3]]
     [,1]  [,2]        
[1,] "due" "2020-03-01"
[2,] "rec" "+1y"       

[[4]]
     [,1]  [,2]        
[1,] "due" "2020-05-01"

Я пробовал различные функции unnest, но не могу понять, как перенести даты выполнения и дату c в свои собственные столбцы.

Любая помощь приветствуется.


Воспроизводимый пример:

library(jsonlite)
library(dplyr)
todo.df <- "[{\"contexts\": [], \"priority\": null, \"projects\": [], \"source\": \"organise website review.  rec:+6m due:2020-02-02\", \"tags\": [[\"rec\", \"+6m\"], [\"due\", \"2020-02-02\"]], \"text\": \"organise website review.\"}, {\"contexts\": [\"smtl\", \"jim\"], \"priority\": \"B\", \"projects\": [], \"source\": \"(B) create wiki page on installing packages @jim @smtl\", \"tags\": [], \"text\": \"create wiki page on installing packages @jim @smtl\"}, {\"contexts\": [\"smtl\", \"jim\"], \"priority\": null, \"projects\": [], \"source\": \"Joomla mobile interface @smtl @jim due:2020-03-01 rec:+1y\", \"tags\": [[\"due\", \"2020-03-01\"], [\"rec\", \"+1y\"]], \"text\": \"Joomla mobile interface @smtl @jim\"}, {\"contexts\": [\"smtl\", \"jim\"], \"priority\": null, \"projects\": [], \"source\": \"review wiki documents @smtl @jim due:2020-05-01\", \"tags\": [[\"due\", \"2020-05-01\"]], \"text\": \"review wiki documents @smtl @jim\"}]" %>% 
  fromJSON(simplifyDataFrame = TRUE) %>%
  as_tibble() %>% 
  select (priority, contexts, projects, tags, text)

Ответы [ 2 ]

2 голосов
/ 04 февраля 2020

Мы можем использовать map_if для создания чистого data.frame, если tags имеет 1+ строк, то позже вы можете сделать обычный unnest

library(dplyr)
library(map)
library(tidyr)
todo.df %>% 
  mutate(tags_cln = map_if(tags, 
                           .p = ~nrow(data.frame(.x))>=1, 
                           .f = ~data.frame(.x, stringsAsFactors = FALSE) %>% 
                                   #Incase we have two or more in due and/or rec, for a simple demo uncomment the following 
                                   #e.g data.frame(todo.df$tags[[1]], stringsAsFactors = FALSE) %>%
                                   group_by(X1) %>% 
                                   mutate(id_r=row_number()) %>% 
                                   spread(X1, X2) %>% 
                                   select(-id_r), 
                           .else = ~data.frame(due=NA_character_, rec=NA_character_))) %>% 
  unnest(tags_cln)


# A tibble: 4 x 7
  priority contexts  projects   tags              text                                               due        rec  
  <chr>    <list>    <list>     <list>            <chr>                                              <chr>      <chr>
1 NA       <chr [0]> <list [0]> <chr[,2] [2 × 2]> organise website review.                           2020-02-02 +6m  
2 B        <chr [2]> <list [0]> <list [0]>        create wiki page on installing packages @jim @smtl NA         NA   
3 NA       <chr [2]> <list [0]> <chr[,2] [2 × 2]> Joomla mobile interface @smtl @jim                 2020-03-01 +1y  
4 NA       <chr [2]> <list [0]> <chr[,2] [1 × 2]> review wiki documents @smtl @jim                   2020-05-01 NA
1 голос
/ 04 февраля 2020

Немного грязное, но рабочее решение:

todo.df$due <- NA
todo.df$rec <- NA
for (line in 1:nrow(todo.df)) {
  found_tags <- todo.df[line, "tags"][[1]][[1]]
  if (length(found_tags) > 0) {
    for (tag_line in 1:nrow(found_tags)) {
      todo.df[line, found_tags[tag_line, 1]] <- found_tags[tag_line, 2]
    }
  }
}
...