Превращение фрейма данных и списка в длинный формат с помощью dplyr - PullRequest
5 голосов
/ 08 июля 2019

Вот загадка.

Предположим, у вас есть фрейм данных и список.В списке столько же элементов, сколько в df строк:

dd <- data.frame(ID=1:3, Name=LETTERS[1:3])
dl <- map(4:6, rnorm) %>% set_names(letters[1:3])

Существует ли простой способ (предпочтительно с dplyr / tidyverse) создать длинный формат, чтобы элементы списка объединялись ссоответствующие строки фрейма данных?Вот то, что я имею в виду, проиллюстрированное не таким элегантным способом:

rows <- map(1:length(dl), ~ rep(., length(dl[[.]]))) %>% unlist()
dd <- dd[rows,]
dd$value <- unlist(dl)

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

Ответы [ 3 ]

10 голосов
/ 08 июля 2019

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

res <- merge(stack(dl), dd, by.x="ind", by.y="Name")

head(res)
#  ind      values ID
#1   A -0.79616693  1
#2   A  0.37720953  1
#3   A  1.30273712  1
#4   A  0.19483859  1
#5   B  0.18770716  2
#6   B -0.02226917  2

Примечание: Я предполагал, что имена для dl должны быть в верхнем регистре, но если они действительно в нижнем регистре, вместо этого должна быть пропущена следующая строка:

res <- merge(stack(setNames(dl, toupper(names(dl)))), dd, by.x="ind", by.y="Name")
7 голосов
/ 08 июля 2019

Поскольку решение dplyr уже было предоставлено, другой вариант заключается в поднаборе dl для каждого Name значения в dd с использованием группировки данных.table

library(data.table)
setDT(dd)

dd[, .(values = dl[[tolower(Name)]]), by = .(ID, Name)]

#     ID Name      values
#  1:  1    A -1.09633600
#  2:  1    A -1.26238190
#  3:  1    A  1.15220845
#  4:  1    A -1.45741071
#  5:  2    B -0.49318131
#  6:  2    B  0.59912670
#  7:  2    B -0.73117632
#  8:  2    B -1.09646143
#  9:  2    B -0.79409753
# 10:  3    C -0.08205888
# 11:  3    C  0.21503398
# 12:  3    C -1.17541571
# 13:  3    C -0.10020616
# 14:  3    C -1.01152362
# 15:  3    C -1.03693337
5 голосов
/ 08 июля 2019

Мы можем создать столбец list и unnest

library(tidyverse)
dd %>% 
  mutate(value = dl) %>% 
  unnest
#   ID Name       value
#1   1    A  1.57984385
#2   1    A  0.66831102
#3   1    A -0.45472145
#4   1    A  2.33807619
#5   2    B  1.56716709
#6   2    B  0.74982763
#7   2    B  0.07025534
#8   2    B  1.31174561
#9   2    B  0.57901536
#10  3    C -1.36629653
#11  3    C -0.66437155
#12  3    C  2.12506187
#13  3    C  1.20220402
#14  3    C  0.10687018
#15  3    C  0.15973401

Обратите внимание, что если критерии основаны на компактности кода, если мы удалим %>%

unnest(mutate(dd, value = dl))

Или другой вариант: uncount и mutate

dd %>% 
   uncount(lengths(dl)) %>%
   mutate(value = flatten_dbl(unname(dl)))

Если требуется соединение на основе имен 'dl'

enframe(dl, name = 'Name') %>%
     mutate(Name = toupper(Name)) %>% 
     left_join(dd) %>% 
     unnest

В base R мы можем rep лицензировать строки 'dd' с lengths из 'dl' и transform, чтобы создать 'значение' как unlist ed 'dl'

transform(dd[rep(seq_len(nrow(dd)), lengths(dl)),], value = unlist(dl))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...