Как скопировать сгруппированные строки в столбец по data.table в R? - PullRequest
0 голосов
/ 02 июля 2018

Я столкнулся с ошибкой памяти при копировании строк в столбцы с использованием техники gather/unite/spread в dplyr в R в другом вопросе здесь ( Как скопировать сгруппированные строки в столбец с помощью dplyr / tidyverse в R? ).

Это фрейм данных, который я использую в качестве примера: (Извините, большая часть этого вопроса просто повторяет предыдущий вопрос)

df <- data.frame(
    hid=c(1,1,1,1,2,2,2,2,2,3,3,3,3),
    mid=c(1,2,3,4,1,2,3,4,5,1,2,3,4),
    tmid=c("010","01010","010","01020",
           "010","0120","010","010","020",
           "010","01010","010","01020"),
    thid=c("010","02020","010","02020",
           "000","0120","010","010","010",
           "010","02020","010","02020")
    )

Мой желаемый вывод показан ниже:

     hid   mid  tmid   thid  tmid_1  tmid_2  tmid_3  tmid_4  tmid_5  thid_1  thid_2  thid_3  thid_4  thid_5
 * <dbl> <dbl> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> 
 1     1     1   010    010    010  01010    010  01020      0    010  02020    010  02020      0
 2     1     2 01010  02020    010  01010    010  01020      0    010  02020    010  02020      0
 3     1     3   010    010    010  01010    010  01020      0    010  02020    010  02020      0
 4     1     4 01020  02020    010  01010    010  01020      0    010  02020    010  02020      0
 5     2     1   010    000    010  0120     010    010    020    000   0120    010    010    010
 6     2     2  0120   0120    010  0120     010    010    020    000   0120    010    010    010
 7     2     3   010    010    010  0120     010    010    020    000   0120    010    010    010
 8     2     4   010    010    010  0120     010    010    020    000   0120    010    010    010
 9     2     5   020    010    010  0120     010    010    020    000   0120    010    010    010
10     3     1   010    010    010  01010    010  01020      0    010  02020    010   02020     0
11     3     2 01010  02020    010  01010    010  01020      0    010  02020    010   02020     0
12     3     3   010    010    010  01010    010  01020      0    010  02020    010   02020     0
13     3     4 01020  02020    010  01010    010  01020      0    010  02020    010   02020     0

Изображение этой операции показано ниже: enter image description here

Что я пытаюсь сделать в этой операции:

  • Преобразование thid и tmid в столбец
  • Номер суффикса в thid_x и tmid_x определяется как mid; однако максимальное число mid не масштабируется (оно увеличивается от 1 до 8-10 в реальном большом наборе данных)
  • mid сгруппирован по hid, чтобы определить, сколько mid хранится в каждом hid
  • Если значение не существует, оно должно быть дополнено 0 (т.е. некоторые hid имеют 5 mid с, а некоторые имеют только 4, поэтому tmid_5 должно быть 0 для таких hid)

Однако, когда я делаю эту операцию, используя метод gather/unite/spread из предыдущего вопроса, он сталкивается с ошибкой памяти, говоря, что не может выделить 11,4 ГБ памяти.

Возможно, причина этой ошибки в том, что функция gather должна создать все комбинации, указанные в ее аргументе, прежде чем разбивать их. Фактический фрейм данных имеет около 80 000 записей, что превышает 16 ГБ ОЗУ в моей 64-битной версии R.

Есть ли у вас какие-либо предложения, чтобы получить тот же результат, не делая такие огромные промежуточные записи? Возможно, data.table может помочь, если он не требует такой промежуточной операции, однако я использовал dplyr и никогда не использовал этот пакет. Я хотел бы, чтобы ваша идея вышла за рамки этой проблемы, и изучил бы новый пакет, основанный на необходимости анализа для дальнейших шагов.

1 Ответ

0 голосов
/ 02 июля 2018

Я думаю, вы можете использовать комбинацию spread и left_join, чтобы получить то, что вам нужно:

library(dplyr)
library(tidyr)

a <- select(df, -thid) %>%
  spread(mid, tmid, sep="_") %>%
  rename_at(vars(matches("^mid_")), funs(paste0("t", .)))
b <- select(df, -tmid) %>%
  spread(mid, thid, sep="_") %>%
  rename_at(vars(matches("^mid_")), funs(gsub("^m", "th", .)))

left_join(df, a, by="hid") %>%
  left_join(b, by="hid")
#    hid mid  tmid  thid tmid_1 tmid_2 tmid_3 tmid_4 tmid_5 thid_1 thid_2 thid_3 thid_4 thid_5
# 1    1   1   010   010    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
# 2    1   2 01010 02020    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
# 3    1   3   010   010    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
# 4    1   4 01020 02020    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
# 5    2   1   010   000    010   0120    010    010    020    000   0120    010    010    010
# 6    2   2  0120  0120    010   0120    010    010    020    000   0120    010    010    010
# 7    2   3   010   010    010   0120    010    010    020    000   0120    010    010    010
# 8    2   4   010   010    010   0120    010    010    020    000   0120    010    010    010
# 9    2   5   020   010    010   0120    010    010    020    000   0120    010    010    010
# 10   3   1   010   010    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
# 11   3   2 01010 02020    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
# 12   3   3   010   010    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>
# 13   3   4 01020 02020    010  01010    010  01020   <NA>    010  02020    010  02020   <NA>

Очистка значений NA должна быть достаточно простой, но может потребоваться перефакторинг их (добавить уровень "0") или просто создать кадр, используя stringsAsFactors=FALSE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...