#r #data.table
#r #data.table
Вопрос:
Я написал код:
df_all<- df1 %>%
mutate(type = factor(type, levels = df3$type)) %>%
group_by(ID, date) %>%
complete(type, fill = list(value = 0)) %>%
left_join(df3)
Как переписать его с помощью data.table? Я новичок в этом, поэтому я не знаю? Было бы просто здорово, если бы вы помогли мне с этим.
Вот для чего я его использую:
У меня есть одноколоночный фрейм данных df3 с типом столбца со всеми возможными «типами»:
comment type
used enter
used open
used close
used update
not_used delete
Я получаю фрейм данных из своей базы данных. Но в этом фрейме данных могут быть не все «типы». Вот пример этой таблицы:
ID date type value
a1 2020-09-01 enter 18
a1 2020-09-01 close 15
a1 2020-09-02 enter 4
a2 2020-09-01 close 10
b1 2020-09-02 update 10
Как вы видите, идентификатор a1 имеет только два типа: ввод и закрытие. у a2 есть только close, у b1 есть только update.
Я хочу связать эти две таблицы таким образом, чтобы «типы», которых не было в моей таблице, имели нулевое значение для каждого идентификатора и даты. Итак, как связать эти две таблицы, чтобы получить это:
comment ID date type value
used a1 2020-09-01 enter 18
used a1 2020-09-01 open 0
used a1 2020-09-01 close 15
used a1 2020-09-01 update 0
not_used a1 2020-09-01 delete 0
used a1 2020-09-02 enter 4
used a1 2020-09-02 open 0
used a1 2020-09-02 close 0
used a1 2020-09-02 update 0
not_used a1 2020-09-02 delete 0
used a2 2020-09-01 enter 0
used a2 2020-09-01 open 0
used a2 2020-09-01 close 10
used a2 2020-09-01 update 0
not_used a2 2020-09-01 delete 0
used b1 2020-09-01 enter 0
used b1 2020-09-01 open 0
used b1 2020-09-01 close 0
used b1 2020-09-01 update 10
not_used b1 2020-09-01 delete 0
Как вы видите, я также сохранил столбец «комментарий». Как я мог переписать код как data.table?
Комментарии:
1. В коде у вас есть
count
столбец. Этого нет в примере2. Что
df3
в коде3. @akrun я отредактировал. его первый фрейм данных
4. @akrun я удалил первую часть rbind, теперь это просто df1
5. В примере это второй пример ‘df1’ и первый ‘df3’?
Ответ №1:
Вот краткая data.table
версия кода OP:
setDT(df1)[, .SD[df3, on = .(type)], by = .(ID, date)]
который возвращает ожидаемый результат (для ясности, NA
s в value
столбце преобразуются на втором шаге — см. Ниже)
ID date type value comment 1: a1 2020-09-01 enter 18 used 2: a1 2020-09-01 open NA used 3: a1 2020-09-01 close 15 used 4: a1 2020-09-01 update NA used 5: a1 2020-09-01 delete NA not_used 6: a1 2020-09-02 enter 4 used 7: a1 2020-09-02 open NA used 8: a1 2020-09-02 close NA used 9: a1 2020-09-02 update NA used 10: a1 2020-09-02 delete NA not_used 11: a2 2020-09-01 enter NA used 12: a2 2020-09-01 open NA used 13: a2 2020-09-01 close 10 used 14: a2 2020-09-01 update NA used 15: a2 2020-09-01 delete NA not_used 16: b1 2020-09-02 enter NA used 17: b1 2020-09-02 open NA used 18: b1 2020-09-02 close NA used 19: b1 2020-09-02 update 10 used 20: b1 2020-09-02 delete NA not_used
Для каждой группы уникальных ID
date
комбинаций подмножество строк из df1
соединяется с правой df3
type
, которая завершает недостающие строки для каждого подмножества. Поскольку вместо tidyr::complete() используется правое соединение, здесь нет необходимости принудительно type
учитывать все уровни факторов. Кроме того, data.table
был сохранен порядок df3
строк во время объединения.
Для преобразования NA
s в value
столбце доступно 4 разных подхода, которые все возвращают один и тот же результат:
setDT(df1)[, .SD[df3, on = .(type)], by = .(ID, date)][is.na(value), value := 0L][]
setDT(df1)[, .SD[df3, on = .(type)], by = .(ID, date)][, value := fcoalesce(value, 0L)][]
setDT(df1)[, .SD[df3, on = .(type)], by = .(ID, date)][, value := nafill(value, fill = 0L)][]
setnafill(setDT(df1)[, .SD[df3, on = .(type)], by = .(ID, date)], fill = 0L, cols = "value")[]
ID date type value comment 1: a1 2020-09-01 enter 18 used 2: a1 2020-09-01 open 0 used 3: a1 2020-09-01 close 15 used 4: a1 2020-09-01 update 0 used 5: a1 2020-09-01 delete 0 not_used 6: a1 2020-09-02 enter 4 used 7: a1 2020-09-02 open 0 used 8: a1 2020-09-02 close 0 used 9: a1 2020-09-02 update 0 used 10: a1 2020-09-02 delete 0 not_used 11: a2 2020-09-01 enter 0 used 12: a2 2020-09-01 open 0 used 13: a2 2020-09-01 close 10 used 14: a2 2020-09-01 update 0 used 15: a2 2020-09-01 delete 0 not_used 16: b1 2020-09-02 enter 0 used 17: b1 2020-09-02 open 0 used 18: b1 2020-09-02 close 0 used 19: b1 2020-09-02 update 10 used 20: b1 2020-09-02 delete 0 not_used
Ответ №2:
Мы можем преобразовать type
из factor
, использовать CJ
(перекрестное соединение) для расширения по идентификатору, дате и типу
library(data.table)
setDT(df1)[, type := factor(type, levels = unique(df3$type))][,
CJ(ID, date, type = type, unique = TRUE)][df1,
value := value, on = .(ID, date, type)][is.na(value),
value := 0][df3, on = .(type)]
Или это можно сделать с помощью split
setDT(df1)[, type := factor(type, levels = unique(df3$type))]
rbindlist(lapply(split(df1, df1[, .(ID, date)], drop = TRUE),
function(x) x[, CJ(ID, date, type = levels(x$type), unique = TRUE)][x,
value := value, on = .(ID, date, type)][is.na(value), value := 0][]))[df3, on = .(type)]))
-вывод
# ID date type value comment
# 1: a1 2020-09-01 enter 18 used
# 2: a1 2020-09-01 open 0 used
# 3: a1 2020-09-01 close 15 used
# 4: a1 2020-09-01 update 0 used
# 5: a1 2020-09-01 delete 0 not_used
# 6: a2 2020-09-01 enter 0 used
# 7: a2 2020-09-01 open 0 used
# 8: a2 2020-09-01 close 10 used
# 9: a2 2020-09-01 update 0 used
#10: a2 2020-09-01 delete 0 not_used
#11: a1 2020-09-02 enter 4 used
#12: a1 2020-09-02 open 0 used
#13: a1 2020-09-02 close 0 used
#14: a1 2020-09-02 update 0 used
#15: a1 2020-09-02 delete 0 not_used
#16: b1 2020-09-02 enter 0 used
#17: b1 2020-09-02 open 0 used
#18: b1 2020-09-02 close 0 used
#19: b1 2020-09-02 update 10 used
#20: b1 2020-09-02 delete 0 not_used
Комментарии:
1. он говорит об ошибке в
[.data.table
(rbindlist(list(df1, df2))[, : Когда i является data.table (или символьным вектором), столбцы, к которым нужно присоединиться, должны быть указаны с помощью аргумента ‘on =’ (см. ?data.table), путем ввода x (т.Е. отсортированных и, помеченный как сортированный, см. ?setkey), или путем совместного использования имен столбцов между x и i (т. Е. Естественного соединения). Соединения с ключом могут иметь дополнительные преимущества в скорости работы с очень большими данными из-за сортировки x в ОЗУ.2. @french_fries это должно быть из
last step for
CJ `. Я не тестировал это, потому что не было примера. Можете ли вы опубликовать пример для тестирования. Спасибо3. я добавил пример и объяснение
4. @french_fries вы уверены, что синтаксис dplyr работал для вас с
rbind
5. дает ли ваш код желаемый результат с примером dataframe?