Объединение значений из широкого фрейма данных в длинный фрейм данных - PullRequest
2 голосов
/ 05 июля 2019

У меня есть два фрейма данных, один широкий и один длинный:

    long_df = structure(list(PID = c(1001, 1001, 1001, 1002, 1002, 1002, 1002, 
1003), scan_name = c("01_001A", "01_001B", "01_001C", "01_002A", 
"01_002B", "01_002D", "01_002E", "01_003B")), row.names = c(NA, 
-8L), class = c("tbl_df", "tbl", "data.frame"))

wide_df = structure(list(PID = c(1001, 1002, 1003), scan_name_1 = c("01_001A", 
"01_002A", NA), scan_date_1 = structure(c(1206748800, 1240876800, 
NA), class = c("POSIXct", "POSIXt"), tzone = "UTC"), scan_name_2 = c("01_001B", 
"01_002B", "01_003B"), scan_date_2 = structure(c(1238544000, 
1272672000, 1424736000), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    scan_name_3 = c("01_001C", NA, NA), scan_date_3 = structure(c(1301702400, 
    NA, NA), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    scan_name_4 = c(NA, "01_002D", NA), scan_date_4 = structure(c(NA, 
    1400112000, NA), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    scan_name_5 = c(NA, "01_002E", NA), scan_date_5 = structure(c(NA, 
    1430438400, NA), class = c("POSIXct", "POSIXt"), tzone = "UTC")), row.names = c(NA, 
-3L), class = c("tbl_df", "tbl", "data.frame"))

Я пытаюсь получить значения "scan_date_1", "scan_date_2" и т. Д. Из wide_df в long_df.

Вывод, который я пытаюсь получить, выглядит следующим образом:

goal_df = structure(list(PID = c(1001, 1001, 1001, 1002, 1002, 1002, 1002, 
1003), scan_name = c("01_001A", "01_001B", "01_001C", "01_002A", 
"01_002B", "01_002D", "01_002E", "01_003B"), scan_date = structure(c(1206748800, 
1238544000, 1301702400, 1240876800, 1272672000, 1400112000, 1430438400, 
1424736000), class = c("POSIXct", "POSIXt"), tzone = "UTC")), row.names = c(NA, 
-8L), class = c("tbl_df", "tbl", "data.frame"))

Кажется простым, но ни одна из моих попыток с использованием merge / melt / etc, не смогла получиться.Любая помощь очень ценится!(Первый раз с использованием «dput», так что, надеюсь, это воспроизводимый пример)

Ответы [ 2 ]

2 голосов
/ 05 июля 2019

Это можно сделать эффективно с помощью функции melt data.table и ее аргумента patterns:

library(data.table)

setDT(wide_df)

goal_df <- melt(wide_df, measure = patterns("scan_name", "scan_date"), value.name = c("scan_name", "scan_date"))
goal_df <- na.omit(goal_df)

goal_df[, variable := NULL][]
#>     PID scan_name  scan_date
#> 1: 1001   01_001A 2008-03-29
#> 2: 1002   01_002A 2009-04-28
#> 3: 1001   01_001B 2009-04-01
#> 4: 1002   01_002B 2010-05-01
#> 5: 1003   01_003B 2015-02-24
#> 6: 1001   01_001C 2011-04-02
#> 7: 1002   01_002D 2014-05-15
#> 8: 1002   01_002E 2015-05-01

Примечание: версия разработки tidyr ( GitHub ) содержит новые функции pivot_longer и pivot_wider с аналогичными функциями, см. Tidyr-Pivoting . Используя pivot_longer вы можете сделать:

library(dplyr)
library(tidyr)

mutate_at(wide_df, .vars = vars(starts_with("scan")), as.character) %>%
    pivot_longer(-PID, 
        names_to = c(".value", "id"),
        names_pattern = "(scan_date|scan_name)_(.)", 
        values_drop_na = TRUE
    ) %>%
    select(-id)
#> # A tibble: 8 x 3
#>     PID scan_name scan_date 
#>   <dbl> <chr>     <chr>     
#> 1  1001 01_001A   2008-03-29
#> 2  1001 01_001B   2009-04-01
#> 3  1001 01_001C   2011-04-02
#> 4  1002 01_002A   2009-04-28
#> 5  1002 01_002B   2010-05-01
#> 6  1002 01_002D   2014-05-15
#> 7  1002 01_002E   2015-05-01
#> 8  1003 01_003B   2015-02-24

packageVersion("tidyr")
#> ‘0.8.3.9000’
1 голос
/ 05 июля 2019

Этот код удлиняет wide_df, где каждая строка представляет уникальное лицо по событию.

library(magrittr)
pattern <- "^scan_(date|name)_(\\d+)$"

wide_df %>% 
  dplyr::mutate_all(as.character) %>% 
  tidyr::gather(key="key", value="value", -PID) %>% 
  dplyr::mutate(
    event_id  = as.integer(sub(pattern, "\\2", key)),
    key       = sub(pattern, "\\1", key)
  ) %>% 
  tidyr::spread(key=key, value=value) %>%
  dplyr::mutate(
    date  = as.Date(date)
  )

Результат:

# A tibble: 15 x 4
   PID   event_id date       name   
   <chr>    <int> <date>     <chr>  
 1 1001         1 2008-03-29 01_001A
 2 1001         2 2009-04-01 01_001B
 3 1001         3 2011-04-02 01_001C
 4 1001         4 NA         NA     
 5 1001         5 NA         NA     
 6 1002         1 2009-04-28 01_002A
 7 1002         2 2010-05-01 01_002B
 8 1002         3 NA         NA     
 9 1002         4 2014-05-15 01_002D
10 1002         5 2015-05-01 01_002E
11 1003         1 NA         NA     
12 1003         2 2015-02-24 01_003B
13 1003         3 NA         NA     
14 1003         4 NA         NA     
15 1003         5 NA         NA     
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...