Можем ли мы заполнить столбцы новыми полями в R? - PullRequest
1 голос
/ 28 мая 2020

У меня есть набор данных, в котором несколько значений в одной строке / столбце. Некоторые разделены знаком «-». Я пытаюсь правильно разбить столбцы, а затем добавить значения, подразумеваемые знаком «-». Мне удалось получить набор данных в правильном формате, но мне не удалось найти способ создать последовательность между lower и upper.

здесь образец данных (ОБНОВЛЕНИЕ: Фактический набор данных имеет «коды» с буквенными символами):

grp_id <- ("grp1")
name <- ("test")
code <- ("93790, 93797 - 93798, 98960 - 98962, 98966 - 98968, 99078, G1501, G5017")
df <- data.frame(grp_id, name, code)

что я пробовал:

df %>%
  separate_rows(code, sep = ",") %>%
  mutate(rn = row_number()) %>%
  separate(code, sep = "-", into = c("lower", "upper")) %>%
  mutate(upper = case_when(is.na(upper) ~ lower,
                           TRUE ~ upper)) %>%
  mutate(implied = seq(as.numeric(lower), as.numeric(upper), by = 1))

это отлично работает до последнего mutate, где я пытаюсь создать новый столбцы для новых значений.

Ожидаемый результат будет:

group_id  name  lower   upper implied.1  implied.2    rn
grp1      test   97390   97390  na        na          1
grp1      test   97397   97398  na        na          2
grp1      test   98960   98962  *98961*   na          3
grp1      test   G1501                                4
grp1      test   G5017                                5

Итак, вы можете видеть, что в rn 3 было добавлено 98961, так как это было подразумеваемое значение со знаком «-».

Любые предложения, которые я могу попробовать?

РЕДАКТИРОВАТЬ: Поскольку в моем фактическом наборе данных есть несколько буквенных символов, это решение не работает полностью. Я отредактировал, как показано ниже, однако он не работает при последней функции изменения.

df %>%
  separate_rows(code, sep = ",") %>%
  mutate(rn = row_number()) %>%
  separate(code, sep = "-", into = c("lower", "upper")) %>%
  mutate(upper = case_when(is.na(upper) ~ lower,
                           TRUE ~ upper)) %>%
  mutate(lower = case_when(
    str_detect(as.character(lower), '\\D') ~ lower,
    TRUE ~ as.character(as.numeric(lower))), 
    upper = case_when(
      str_detect(as.character(lower), '\\D') ~ lower,
      TRUE ~ as.character(as.numeric(upper)))) %>% 
  rowwise() %>% 
  mutate(implied = list( seq(lower, upper, by = 1))) %>% 
  tidyr::unnest_wider(implied)

1 Ответ

1 голос
/ 28 мая 2020

Используйте dplyr :: rowwise для создания таблицы, сгруппированной по строкам, затем убедитесь, что ваш оператор seq заключен в список. Затем используйте tidyr :: unnest_wider, чтобы разложить список, чтобы получить каждое значение в последовательности в его собственном столбце. Затем вы можете просто переименовать столбцы с помощью rename или rename_at.

Работает ли это для ваших нужд?

df %>%
  separate_rows(code, sep = ",") %>%
  mutate(rn = row_number()) %>%
  separate(code, sep = "-", into = c("lower", "upper")) %>%
  mutate(upper = case_when(is.na(upper) ~ lower,
                           TRUE ~ upper)) %>%
  mutate(lower = as.numeric(lower), upper = as.numeric(upper)) %>% 
  rowwise() %>% 
  mutate(implied = list( seq(lower, upper, by = 1)) ) %>% 
  tidyr::unnest_wider(implied)
# A tibble: 5 x 8
  grp_id name  lower upper    rn  ...1  ...2  ...3
  <chr>  <chr> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
1 grp1   test  93790 93790     1 93790    NA    NA
2 grp1   test  93797 93798     2 93797 93798    NA
3 grp1   test  98960 98962     3 98960 98961 98962
4 grp1   test  98966 98968     4 98966 98967 98968
5 grp1   test  99078 99078     5 99078    NA    NA

UPDATE для обработки альфа-символов:

df %>%
  separate_rows(code, sep = ",") %>%
  mutate(rn = row_number()) %>%
  separate(code, sep = "-", into = c("lower", "upper")) %>% 
  mutate(lower = str_trim(lower),
         upper = str_trim(upper),
         alpha = str_extract(lower, "[A-Z]+"),
         lower = parse_number(lower),
         upper = case_when(
           !is.na(alpha) ~ as.character(NA),
           is.na(upper) ~ as.character(lower),
           TRUE ~ as.character(upper)
         ),
         upper = as.numeric(upper)
  ) %>% 
  rowwise() %>% 
  mutate(implied = ifelse(
    is.na(alpha), list( seq(lower, upper, by = 1)), NA
      )
    ) %>% 
  tidyr::unnest_wider(implied) %>% 
  unite(alpha, lower, col = lower, sep = "", na.rm = TRUE)
# A tibble: 7 x 8
  grp_id name  lower upper    rn  ...1  ...2  ...3
  <chr>  <chr> <chr> <dbl> <int> <dbl> <dbl> <dbl>
1 grp1   test  93790 93790     1 93790    NA    NA
2 grp1   test  93797 93798     2 93797 93798    NA
3 grp1   test  98960 98962     3 98960 98961 98962
4 grp1   test  98966 98968     4 98966 98967 98968
5 grp1   test  99078 99078     5 99078    NA    NA
6 grp1   test  G1501    NA     6    NA    NA    NA
7 grp1   test  G5017    NA     7    NA    NA    NA
...