У меня есть такие данные:
library(data.table)
id <- c("1232","1232","1232","4211","4211","4211")
conversion <- c(0,0,0,1,1,1)
DT <- data.table(id, conversion)
id date conversion
1232 2018-01-01 0
1232 2018-01-03 0
1232 2018-01-04 0
4211 2018-04-01 1
4211 2018-04-04 1
4211 2018-04-06 1
Я хотел бы создать двоичное значение только для последней строки каждой группы на основе строки идентификатора. Двоичный файл будет равен 1 только тогда, когда преобразование равно 1 для группы.
id date conversion lastconv
1232 2018-01-01 0 0
1232 2018-01-03 0 0
1232 2018-01-04 0 0
4211 2018-04-01 1 0
4211 2018-04-04 1 0
4211 2018-04-06 1 1
Я пытался использовать несколько примеров с параметром «mult» в data.table, но возвращал только ошибки.
DT[unique(id), lastconv := 1, mult = "last"]
Вы пробовали что-то вроде следующего?
library(tidyverse)
final_conversion_dat <- DT %>%
group_by(id) %>%
mutate(date = as.Date(date),
final_conversion = ifelse(date == max(date, na.rm = T) & conversion == 1, 1, 0))
Отфильтруйте последнюю строку в группе и установите lastconv
равным conversion
.
DT[DT[, .I[.N], by=id]$V1, lastconv := conversion]
Затем замените NA
s на 0
DT[is.na(lastconv), lastconv := 0L]
Результат
DT
# id conversion lastconv
#1: 1232 0 0
#2: 1232 0 0
#3: 1232 0 0
#4: 4211 1 0
#5: 4211 1 0
#6: 4211 1 1
Если установлена data.table
v1.12.3, мы также можем использовать новую функцию setnafill
для замены NA
s на втором шаге.
DT[DT[, .I[.N], by=id]$V1, lastconv := conversion]
setnafill(DT, cols = "lastconv", fill = 0L)
приятно видеть, что пользователи публикуют последние функции! спасибо, больше информации об этой новой функции в файле НОВОСТИ или в руководство
Для каждого идентификатора проверьте, является ли номер строки последним номером строки в группе, и если «преобразование» равно 1. Преобразуйте логический результат в целое число.
DT[ , lastconv := as.integer(.I == .I[.N] & conversion == 1), by = id]
Изменение кода OP для присоединения к последней строке каждой группы:
DT[, v := 0]
DT[.(DT[conversion == 1, unique(id)]), on=.(id), mult = "last", v := 1]
id conversion v
1: 1232 0 0
2: 1232 0 0
3: 1232 0 0
4: 4211 1 0
5: 4211 1 0
6: 4211 1 1
Это отличается только тем, что он выбирает, какие id
редактировать, исходя из желаемого условия.
Сроки для справки:
library(data.table)
#data.table 1.12.3 IN DEVELOPMENT built 2019-05-12 17:04:48 UTC; root using 4 threads (see ?getDTthreads). Latest news: r-datatable.com
set.seed(0L)
nid <- 3e6L
DT <- data.table(id=rep(1L:nid, each=3L))[,
conversion := sample(c(0L,1L), 1L, replace=TRUE), by=.(id)]
DT0 <- copy(DT)
DT1 <- copy(DT)
DT2 <- copy(DT)
DT3 <- copy(DT)
mtd0 <- function() {
DT0[DT0[, .I[.N], by=id]$V1, lastconv := conversion]
DT0[is.na(lastconv), lastconv := 0L]
}
mtd1 <- function() {
DT1[DT1[, .I[.N], by=id]$V1, lastconv := conversion]
setnafill(DT1, cols = "lastconv", fill = 0L)
}
mtd2 <- function() {
DT2[, v := 0]
DT2[.(DT2[conversion == 1, unique(id)]), on=.(id), mult = "last", v := 1]
#or also
#DT2[, v := 0L][
# DT2[,.(cv=last(conversion)), id], on=.(id), mult = "last", v := cv]
}
mtd3 <- function() {
DT3[ , lastconv := as.integer(.I == .I[.N] & conversion == 1), by = id]
}
library(microbenchmark)
microbenchmark(mtd0(), mtd1(), mtd2(), mtd3(), times=1L)
тайминги:
Unit: milliseconds
expr min lq mean median uq max neval cld
mtd0() 1363.1783 1416.1867 1468.9256 1469.1952 1521.7992 1574.4033 3 b
mtd1() 1349.5333 1365.4653 1378.9350 1381.3974 1393.6358 1405.8743 3 b
mtd2() 511.5615 515.4728 552.9133 519.3841 573.5892 627.7944 3 a
mtd3() 3966.8867 4009.1128 4048.9607 4051.3389 4089.9977 4128.6564 3 c
Ваш пример сработал бы, если бы у вас было
setkey
перед выполнением вашей строки. Обратите внимание, чтоmult = "last"
также приведет к тому, что 1 будет размещено на идентификаторе 1232.