data.table 相当于 tidyr::complete()
data.table equivalent of tidyr::complete()
tidyr::complete()
将行添加到 data.frame
以获取数据中缺失的列值的组合。示例:
library(dplyr)
library(tidyr)
df <- data.frame(person = c(1,2,2),
observation_id = c(1,1,2),
value = c(1,1,1))
df %>%
tidyr::complete(person,
observation_id,
fill = list(value=0))
产量
# A tibble: 4 × 3
person observation_id value
<dbl> <dbl> <dbl>
1 1 1 1
2 1 2 0
3 2 1 1
4 2 2 1
其中 person == 1
和 observation_id == 2
组合中 df
中缺失的 value
已用值 0 填充。
在 data.table
中这相当于什么?
可能有更好的答案,但这个有效:
dt[CJ(person=unique(dt$person),
observation_id=unique(dt$observation_id)),
on=c('person','observation_id')]
给出:
person observation_id value
1: 1 1 1
2: 2 1 1
3: 1 2 NA
4: 2 2 1
现在,如果您希望能够填充任何值(而不是 NA
),我建议您等待 corresponding feature 完成或贡献它:)
我认为 data.table 的哲学需要比 tidyverse 中更少的任务特殊命名函数,因此需要一些额外的编码,例如:
res = setDT(df)[
CJ(person = person, observation_id = observation_id, unique=TRUE),
on=.(person, observation_id)
]
在此之后,您仍然需要手动处理缺失级别的值填充。我们可以使用 setnafill
来有效地处理这个问题,并在最近版本的 data.table
:
中引用
setnafill(res, fill = 0, cols = 'value')
请参阅 了解可回避此问题的功能。
当然,这里必须输入三遍列名,这太疯狂了。但另一方面,可以写一个包装器:
completeDT <- function(DT, cols, defs = NULL){
mDT = do.call(CJ, c(DT[, ..cols], list(unique=TRUE)))
res = DT[mDT, on=names(mDT)]
if (length(defs))
res[, names(defs) := Map(replace, .SD, lapply(.SD, is.na), defs), .SDcols=names(defs)]
res[]
}
completeDT(setDT(df), cols = c("person", "observation_id"), defs = c(value = 0))
person observation_id value
1: 1 1 1
2: 1 2 0
3: 2 1 1
4: 2 2 1
作为避免在第一步中输入三次名称的快速方法,这是@thelatemail 的想法:
vars <- c("person","observation_id")
df[do.call(CJ, c(mget(vars), unique=TRUE)), on=vars]
# or with magrittr...
c("person","observation_id") %>% df[do.call(CJ, c(mget(.), unique=TRUE)), on=.]
更新:由于@MichaelChirico 和@MattDowle the improvement.
,现在您无需在 CJ 中输入两次姓名
值得注意的是,上面的 completeDT
函数不具备 tidyr::complete
的许多功能。特别是,空因子水平被删除 - 不像 tidyr::complete
保留它们。如果您确实想保留空因子,可以按如下方式编辑该函数。下面的 make_vals
函数可以更复杂地处理其他变量 类 例如。整数的完整序列。
library(magrittr)
library(data.table)
dat <- data.frame(
person = c(1,2,2),
observation_id = factor(c(1,1,2), 1:3),
value = c(1,1,1))
dat %>%
tidyr::complete(
person, observation_id, fill = list(value=0))
#> # A tibble: 6 x 3
#> person observation_id value
#> <dbl> <fct> <dbl>
#> 1 1 1 1
#> 2 1 2 0
#> 3 1 3 0
#> 4 2 1 1
#> 5 2 2 1
#> 6 2 3 0
completeDT <- function(DT, cols, defs = NULL){
make_vals <- function(col) {
if(is.factor(col)) factor(levels(col))
else unique(col)
}
mDT = do.call(CJ, c(lapply(DT[, ..cols], make_vals), list(unique=TRUE)))
res = DT[mDT, on=names(mDT)]
if (length(defs))
res[, names(defs) := Map(replace, .SD, lapply(.SD, is.na), defs), .SDcols=names(defs)]
res[]
}
completeDT(DT = setDT(dat), cols = c("person", "observation_id"), defs = c(value = 0))
#> person observation_id value
#> 1: 1 1 1
#> 2: 1 2 0
#> 3: 1 3 0
#> 4: 2 1 1
#> 5: 2 2 1
#> 6: 2 3 0
由 reprex package (v0.3.0)
于 2021 年 3 月 8 日创建
tidyr::complete()
将行添加到 data.frame
以获取数据中缺失的列值的组合。示例:
library(dplyr)
library(tidyr)
df <- data.frame(person = c(1,2,2),
observation_id = c(1,1,2),
value = c(1,1,1))
df %>%
tidyr::complete(person,
observation_id,
fill = list(value=0))
产量
# A tibble: 4 × 3
person observation_id value
<dbl> <dbl> <dbl>
1 1 1 1
2 1 2 0
3 2 1 1
4 2 2 1
其中 person == 1
和 observation_id == 2
组合中 df
中缺失的 value
已用值 0 填充。
在 data.table
中这相当于什么?
可能有更好的答案,但这个有效:
dt[CJ(person=unique(dt$person),
observation_id=unique(dt$observation_id)),
on=c('person','observation_id')]
给出:
person observation_id value
1: 1 1 1
2: 2 1 1
3: 1 2 NA
4: 2 2 1
现在,如果您希望能够填充任何值(而不是 NA
),我建议您等待 corresponding feature 完成或贡献它:)
我认为 data.table 的哲学需要比 tidyverse 中更少的任务特殊命名函数,因此需要一些额外的编码,例如:
res = setDT(df)[
CJ(person = person, observation_id = observation_id, unique=TRUE),
on=.(person, observation_id)
]
在此之后,您仍然需要手动处理缺失级别的值填充。我们可以使用 setnafill
来有效地处理这个问题,并在最近版本的 data.table
:
setnafill(res, fill = 0, cols = 'value')
请参阅
当然,这里必须输入三遍列名,这太疯狂了。但另一方面,可以写一个包装器:
completeDT <- function(DT, cols, defs = NULL){
mDT = do.call(CJ, c(DT[, ..cols], list(unique=TRUE)))
res = DT[mDT, on=names(mDT)]
if (length(defs))
res[, names(defs) := Map(replace, .SD, lapply(.SD, is.na), defs), .SDcols=names(defs)]
res[]
}
completeDT(setDT(df), cols = c("person", "observation_id"), defs = c(value = 0))
person observation_id value
1: 1 1 1
2: 1 2 0
3: 2 1 1
4: 2 2 1
作为避免在第一步中输入三次名称的快速方法,这是@thelatemail 的想法:
vars <- c("person","observation_id")
df[do.call(CJ, c(mget(vars), unique=TRUE)), on=vars]
# or with magrittr...
c("person","observation_id") %>% df[do.call(CJ, c(mget(.), unique=TRUE)), on=.]
更新:由于@MichaelChirico 和@MattDowle the improvement.
,现在您无需在 CJ 中输入两次姓名值得注意的是,上面的 completeDT
函数不具备 tidyr::complete
的许多功能。特别是,空因子水平被删除 - 不像 tidyr::complete
保留它们。如果您确实想保留空因子,可以按如下方式编辑该函数。下面的 make_vals
函数可以更复杂地处理其他变量 类 例如。整数的完整序列。
library(magrittr)
library(data.table)
dat <- data.frame(
person = c(1,2,2),
observation_id = factor(c(1,1,2), 1:3),
value = c(1,1,1))
dat %>%
tidyr::complete(
person, observation_id, fill = list(value=0))
#> # A tibble: 6 x 3
#> person observation_id value
#> <dbl> <fct> <dbl>
#> 1 1 1 1
#> 2 1 2 0
#> 3 1 3 0
#> 4 2 1 1
#> 5 2 2 1
#> 6 2 3 0
completeDT <- function(DT, cols, defs = NULL){
make_vals <- function(col) {
if(is.factor(col)) factor(levels(col))
else unique(col)
}
mDT = do.call(CJ, c(lapply(DT[, ..cols], make_vals), list(unique=TRUE)))
res = DT[mDT, on=names(mDT)]
if (length(defs))
res[, names(defs) := Map(replace, .SD, lapply(.SD, is.na), defs), .SDcols=names(defs)]
res[]
}
completeDT(DT = setDT(dat), cols = c("person", "observation_id"), defs = c(value = 0))
#> person observation_id value
#> 1: 1 1 1
#> 2: 1 2 0
#> 3: 1 3 0
#> 4: 2 1 1
#> 5: 2 2 1
#> 6: 2 3 0
由 reprex package (v0.3.0)
于 2021 年 3 月 8 日创建