Как разделить этот столбец с несколькими типами данных на [['education', 'Ph.D., MIT'] ... на несколько столбцов? - PullRequest
1 голос
/ 26 апреля 2019

У меня есть столбец с несколькими типами данных внутри разных типов.Это JSON-esque, но я не совсем знаю, как заставить это работать с jsonlite или tidyr::separate.Как я могу разбить это на несколько столбцов?

library(tidyverse)

tribble(~ID, ~data,
        "A", "[['education', 'Ph.D., MIT'], ['interests', 'Econometrics, Causal Inference']]",
        "B", "[['function', 'Social']]",
        "C", "[['research_interests', 'S&P']]",
        "D", "[['field', 'American Politics']]")

Мой ожидаемый результат будет что-то вроде: enter image description here

Ответы [ 2 ]

1 голос
/ 26 апреля 2019

Аналогично MillionC - это своего рода метод грубой силы, в котором делается довольно много предположений о данных:

library(tidyverse)

tribble(~ID, ~data,
        "A", "[['education', 'Ph.D., MIT'], ['interests', 'Econometrics, Causal Inference']]",
        "B", "[['function', 'Social']]",
        "C", "[['research_interests', 'S&P']]",
        "D", "[['field', 'American Politics']]") -> df

df %>% 
  separate(data, into = c("x1", "x2"), sep = "\\], \\[") %>% 
  gather(x, data, -ID, na.rm = T) %>% 
  separate(data, into = c("k", "v"), sep = "', '") %>%
  mutate_at(vars(k:v), ~gsub("\\[|]|'", "", .)) %>% 
  select(-x) %>% 
  spread(k, v)
#> # A tibble: 4 x 6
#>   ID    education  field      `function` interests         research_intere…
#>   <chr> <chr>      <chr>      <chr>      <chr>             <chr>           
#> 1 A     Ph.D., MIT <NA>       <NA>       Econometrics, Ca… <NA>            
#> 2 B     <NA>       <NA>       Social     <NA>              <NA>            
#> 3 C     <NA>       <NA>       <NA>       <NA>              S&P             
#> 4 D     <NA>       American … <NA>       <NA>              <NA>

Создано в 2019-04-26 в Представить пакет (v0.2.1)

1 голос
/ 26 апреля 2019

Я уверен, что, возможно, есть более элегантный способ сделать это, но посмотрите, дает ли это желаемый результат:

library(tidyverse)

data <- tribble(~ID, ~data,
        "A", "[['education', 'Ph.D., MIT'], ['interests', 'Econometrics, Causal Inference']]",
        "B", "[['function', 'Social']]",
        "C", "[['research_interests', 'S&P']]",
        "D", "[['field', 'American Politics']]")

column_names <- str_extract_all(data$data, "\\['(?<=').*?(?=')")
column_names <- map(column_names, ~ str_remove(.x, "\\['"))
names(column_names) <- data$ID

values <- str_extract_all(data$data, ",[:space:]'(?<=').*?(?=')")
values <- map(values, ~ str_remove(.x, ",[:space:]'")) 
names(values) <- data$ID

val_df <- data.frame(values)%>%
            gather("ID", "val")
col_df <- data.frame(column_names)%>%
            gather("ID", "col")

bind_cols(col_df, val_df) %>%
  distinct()%>%
  spread(col, val, fill = NA)%>%
  select(-ID1)

К сожалению, этот подход зависит как минимум от двух предположений:

  1. Имена столбцов всегда находятся в следующем формате "['column_name'"
  2. Значения всегда находятся в следующем формате ", 'value']"

Я не уверен, будет ли масштабироваться до остальной части ваших данных, но дайте мне знать, если это работает.

Изменить для добавления дополнительных критериев в комментариях

Если один идентификатор имеет две записи дляВ одном столбце у вас есть как минимум две опции:

  1. Создать вторую запись для идентификатора
  2. paste из двух значений в одно значение

Вот дополнительная примерная запись из комментариев (с моими правками «исследовательский интерес» к «исследовательский интерес с », при условии, что они должны совпадать с исходными данными):

"E", "[['research_interests', 'American Politics'], ['research_interests', 'Democratization']]"

Вариант 1: создать вторую запись

Это должно датьдве записи для 'E'

# Replace last step of the original answer with this:
two_records <- bind_cols(col_df, val_df) %>%
                distinct()%>%
                group_by(col)%>%
                mutate(grouped_id = row_number()) %>%
                spread(col, val, fill = NA)%>%
                select(-ID1, -grouped_id)

Вариант 2. Вставьте два значения в 1

Это больше похоже на ваш исходный желаемый результат

# Replace last step of original answer with this:
paste_records <- bind_cols(col_df, val_df) %>%
                  distinct()%>%
                  group_by(col)%>%
                  mutate(grouped_id = row_number()) %>%
                  spread(col, val, fill = NA)%>%
                  select(-ID1, -grouped_id)

paste_records <- paste_records %>%
  split(paste_records$ID)%>%
  map_df(mutate_if, function(x)length(unique(x))>1, .funs = list(function(x)paste(x,collapse = ", ")))%>%
  distinct()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...