R data.table 使用 lapply 创建自定义函数以创建和重新分配多个变量
R data.table creating a custom function using lapply to create and reassign multiple variables
我有以下几行代码:
DT[flag==T, temp:=haz_1.5]
DT[, temp:= na.locf(temp, na.rm = FALSE), "pid"]
DT[agedays==61, haz_1.5_1:=temp]
我需要将它转换成一个函数,这样它就可以处理一系列变量,而不仅仅是一个变量。我最近学习了如何使用 lapply 通过传递列列表和创建一组新列的条件来创建函数。但是,当我遍历列列表以及在这些列上传递变量的所有值时,我不确定该怎么做。
例如,我可以编写以下代码:
columns<-c("haz_1.5", "waz_1.5")
new_cols <- paste(columns, "1", sep = "_")
x=61
maled_anthro[(flag==TRUE)&(agedays==x), (new_cols) := lapply(.SD, function(y) na.locf(y, na.rm=F)), .SDcols = columns]
但是我错过了 na.locf 步骤,因此在构建函数之前没有得到与原始代码行相同的输出。我如何将利用 na.locf 结转值 (DT[ temp:= na.locf(temp, na.rm = FALSE), "pid"]) 的代码行合并到此以一种将所有数据包装到单个函数中的方式运行?这会以同样的方式与 lapply 一起使用吗?
与我正在使用的数据 table 相似的虚拟数据:
DT <- data.table(pid = c(1,1,2,3,3,4,4,5,5,5),
flag = c(T,T,F,T,T,F,T,T,T,T),
agedays = c(1,61,61,51,61,23,61,1,32,61),
haz_1.5 = c(1,1,1,2,NA,1,3,2,3,4),
waz_1.5 = c(1,NA,NA,NA,NA,2,2,3,4,4))
OP的代码可以变成一个匿名函数,应用于所选的columns
:
library(data.table)
columns <- c("haz_1.5", "waz_1.5")
new_cols <- paste0(columns, "_1")
x <- 61
DT[, (new_cols) := lapply(.SD, function(v) {
temp <- fifelse(flag, v, NA_real_)
temp <- nafill(temp, "locf")
fifelse(agedays == x, temp, NA_real_)
}), .SDcols = columns, by = pid][]
pid flag agedays haz_1.5 waz_1.5 haz_1.5_1 waz_1.5_1
1: 1 TRUE 1 1 1 NA NA
2: 1 TRUE 61 1 NA 1 1
3: 2 FALSE 61 1 NA NA NA
4: 3 TRUE 51 2 NA NA NA
5: 3 TRUE 61 NA NA 2 NA
6: 4 FALSE 23 1 2 NA NA
7: 4 TRUE 61 3 2 3 2
8: 5 TRUE 1 2 3 NA NA
9: 5 TRUE 32 3 4 NA NA
10: 5 TRUE 61 4 4 4 4
这与我们为两列手动重复 OP 的代码时得到的结果相同(请注意,在通过引用分配[=42]之前需要清除 temp
列=] 的一部分。)
DT[(flag), temp := haz_1.5]
DT[, temp := zoo::na.locf(temp, na.rm = FALSE), by = pid]
DT[agedays == 61, haz_1.5_1 := temp]
DT[, temp := NULL]
DT[(flag), temp := waz_1.5]
DT[, temp := zoo::na.locf(temp, na.rm = FALSE), by = pid]
DT[agedays == 61, waz_1.5_1 := temp]
DT[, temp := NULL][]
pid flag agedays haz_1.5 waz_1.5 haz_1.5_1 waz_1.5_1
1: 1 TRUE 1 1 1 NA NA
2: 1 TRUE 61 1 NA 1 1
3: 2 FALSE 61 1 NA NA NA
4: 3 TRUE 51 2 NA NA NA
5: 3 TRUE 61 NA NA 2 NA
6: 4 FALSE 23 1 2 NA NA
7: 4 TRUE 61 3 2 3 2
8: 5 TRUE 1 2 3 NA NA
9: 5 TRUE 32 3 4 NA NA
10: 5 TRUE 61 4 4 4 4
一些解释
- OP 的“单列”代码与此方法之间有一个重要区别:为分组变量中的每个项目调用匿名函数
pid
。在 OP 的代码中,第一个和最后一个分配是在未分组的(完整的)向量上工作的(这可能会更有效,也许)。但是,这些赋值的结果与 pid
无关,结果是相同的。
- 而不是
zoo::na.locf()
,data.table 的 nafill()
函数被使用(新的 data.table v1.12.4,在 CRAN 2019 年 10 月 3 日)
DT[(flag), ...]
等同于 DT[flag == TRUE, ...]
- 当使用
fifelse()
而不是子集 通过引用分配 时,no
参数必须是 NA
才能符合要求。因此,DT[, temp := fifelse(flag, haz_1.5, NA_real_)][]
等同于 DT[(flag), temp := haz_1.5][]
我有以下几行代码:
DT[flag==T, temp:=haz_1.5]
DT[, temp:= na.locf(temp, na.rm = FALSE), "pid"]
DT[agedays==61, haz_1.5_1:=temp]
我需要将它转换成一个函数,这样它就可以处理一系列变量,而不仅仅是一个变量。我最近学习了如何使用 lapply 通过传递列列表和创建一组新列的条件来创建函数。但是,当我遍历列列表以及在这些列上传递变量的所有值时,我不确定该怎么做。
例如,我可以编写以下代码:
columns<-c("haz_1.5", "waz_1.5")
new_cols <- paste(columns, "1", sep = "_")
x=61
maled_anthro[(flag==TRUE)&(agedays==x), (new_cols) := lapply(.SD, function(y) na.locf(y, na.rm=F)), .SDcols = columns]
但是我错过了 na.locf 步骤,因此在构建函数之前没有得到与原始代码行相同的输出。我如何将利用 na.locf 结转值 (DT[ temp:= na.locf(temp, na.rm = FALSE), "pid"]) 的代码行合并到此以一种将所有数据包装到单个函数中的方式运行?这会以同样的方式与 lapply 一起使用吗?
与我正在使用的数据 table 相似的虚拟数据:
DT <- data.table(pid = c(1,1,2,3,3,4,4,5,5,5),
flag = c(T,T,F,T,T,F,T,T,T,T),
agedays = c(1,61,61,51,61,23,61,1,32,61),
haz_1.5 = c(1,1,1,2,NA,1,3,2,3,4),
waz_1.5 = c(1,NA,NA,NA,NA,2,2,3,4,4))
OP的代码可以变成一个匿名函数,应用于所选的columns
:
library(data.table)
columns <- c("haz_1.5", "waz_1.5")
new_cols <- paste0(columns, "_1")
x <- 61
DT[, (new_cols) := lapply(.SD, function(v) {
temp <- fifelse(flag, v, NA_real_)
temp <- nafill(temp, "locf")
fifelse(agedays == x, temp, NA_real_)
}), .SDcols = columns, by = pid][]
pid flag agedays haz_1.5 waz_1.5 haz_1.5_1 waz_1.5_1 1: 1 TRUE 1 1 1 NA NA 2: 1 TRUE 61 1 NA 1 1 3: 2 FALSE 61 1 NA NA NA 4: 3 TRUE 51 2 NA NA NA 5: 3 TRUE 61 NA NA 2 NA 6: 4 FALSE 23 1 2 NA NA 7: 4 TRUE 61 3 2 3 2 8: 5 TRUE 1 2 3 NA NA 9: 5 TRUE 32 3 4 NA NA 10: 5 TRUE 61 4 4 4 4
这与我们为两列手动重复 OP 的代码时得到的结果相同(请注意,在通过引用分配[=42]之前需要清除 temp
列=] 的一部分。)
DT[(flag), temp := haz_1.5]
DT[, temp := zoo::na.locf(temp, na.rm = FALSE), by = pid]
DT[agedays == 61, haz_1.5_1 := temp]
DT[, temp := NULL]
DT[(flag), temp := waz_1.5]
DT[, temp := zoo::na.locf(temp, na.rm = FALSE), by = pid]
DT[agedays == 61, waz_1.5_1 := temp]
DT[, temp := NULL][]
pid flag agedays haz_1.5 waz_1.5 haz_1.5_1 waz_1.5_1 1: 1 TRUE 1 1 1 NA NA 2: 1 TRUE 61 1 NA 1 1 3: 2 FALSE 61 1 NA NA NA 4: 3 TRUE 51 2 NA NA NA 5: 3 TRUE 61 NA NA 2 NA 6: 4 FALSE 23 1 2 NA NA 7: 4 TRUE 61 3 2 3 2 8: 5 TRUE 1 2 3 NA NA 9: 5 TRUE 32 3 4 NA NA 10: 5 TRUE 61 4 4 4 4
一些解释
- OP 的“单列”代码与此方法之间有一个重要区别:为分组变量中的每个项目调用匿名函数
pid
。在 OP 的代码中,第一个和最后一个分配是在未分组的(完整的)向量上工作的(这可能会更有效,也许)。但是,这些赋值的结果与pid
无关,结果是相同的。 - 而不是
zoo::na.locf()
,data.table 的nafill()
函数被使用(新的 data.table v1.12.4,在 CRAN 2019 年 10 月 3 日) DT[(flag), ...]
等同于DT[flag == TRUE, ...]
- 当使用
fifelse()
而不是子集 通过引用分配 时,no
参数必须是NA
才能符合要求。因此,DT[, temp := fifelse(flag, haz_1.5, NA_real_)][]
等同于DT[(flag), temp := haz_1.5][]