如何用 na.spline 替换 data.table 中的 NA 值
How to replace NA values in a data.table with na.spline
我正在尝试准备一些从欧盟统计局检索到的人口统计数据以供进一步处理,其中包括用相应的近似数据替换任何缺失的数据。
起初我只使用 data.frames,但后来我确信 data.tables 可能比常规 data.frames 有一些优势,所以我迁移到 data.tables。
我在这样做时观察到的一件事是,将 "na.spline" 与 "apply" 结合使用与 "na.spline" 作为 data.table 的一部分时会得到不同的结果。
#1源数据
(dt0 <- data.table(
"age,sex,geo\time" = c("TOTAL,F,AD", "TOTAL,F,AL", "TOTAL,F,AM", "TOTAL,F,AT", "TOTAL,F,AZ"),
"2014" = c(NA, NA, NA, 4351253, NA),
"2013" = c(37408, NA, NA, 4328238, 4707690),
"2012" = c(38252, NA, 1684000, 4309977, 4651601),
"2011" = c(38252, 1409931, 1679066, 4296293, 4594023),
"2010" = c(40296, NA, 1673656, 4285442, 4542083)
))
生成
age,sex,geo\time 2014 2013 2012 2011 2010
1: TOTAL,F,AD NA 37408 38252 38252 40296
2: TOTAL,F,AL NA NA NA 1409931 NA
3: TOTAL,F,AM NA NA 1684000 1679066 1673656
4: TOTAL,F,AT 4351253 4328238 4309977 4296293 4285442
5: TOTAL,F,AZ NA 4707690 4651601 4594023 4542083
分成"row headings"...
(dt0a <- dt0[, 1, with=FALSE])
(cn0a <- colnames(dt0a))
...和人口数据...
(dt0b <- dt0[, 2:ncol(dt0), with=FALSE])
(cn0ba <- colnames(dt0b))
#2 将 NAs 替换为 "na.spline" & "apply"
(dt1b <- data.table(t(apply(dt0b, 1, na.spline, na.rm=FALSE))))
(setnames(dt1b, cn0b))
(dt1 <- cbind(dt0a, dt1b))
这导致...
age,sex,geo\time 2014 2013 2012 2011 2010
1: TOTAL,F,AD 32832 37408 38252 38252 40296
2: TOTAL,F,AL 1409931 1409931 1409931 1409931 1409931
3: TOTAL,F,AM 1692440 1688458 1684000 1679066 1673656
4: TOTAL,F,AT 4351253 4328238 4309977 4296293 4285442
5: TOTAL,F,AZ 4755163 4707690 4651601 4594023 4542083
#3 在 "data.table"
内替换 NAs
(dt2b <- dt0b[,lapply(.SD, na.spline, na.rm=FALSE)])
(dt2 <- cbind(dt0a, dt2b))
瞧瞧...
age,sex,geo\time 2014 2013 2012 2011 2010
1: TOTAL,F,AD 4351253 37408 38252.0 38252 40296.0
2: TOTAL,F,AL 4351253 1993097 -611513.8 1409931 -629363.2
3: TOTAL,F,AM 4351253 3423374 1684000.0 1679066 1673656.0
4: TOTAL,F,AT 4351253 4328238 4309977.0 4296293 4285442.0
5: TOTAL,F,AZ 4351253 4707690 4651601.0 4594023 4542083.0
#4 比较结果
(identical(dt1, dt2))
考虑到上述情况并不令人意外...
[1] FALSE
(用方法 #2 计算的替代 NAs 的值是我感兴趣的值,仅通过方法 #3 生成)。
追求 "data.table" 路线(方法 #3)的原因之一是性能(正如在各种帖子中指出的那样,当使用 "apply" 时,矩阵运算正在执行,这比仅促进 "data.table" 的相应方法花费的时间要长得多)。
作为 RI 的新手,我想我做了一些根本性的错误,唯一的问题是,我一点也不知道这可能是什么。
非常感谢能为我指明正确方向的任何帮助!
-Sil68
您在 apply
版本中进行行向运算,在 data.table
版本中进行列向运算。如果设置 by = 1:nrow(dt)
,则可以在 data.table
中进行按行操作。
dt2b <- dt0b[, as.list(na.spline(unlist(.SD), na.rm=FALSE)), by = 1:nrow(dt0b)]
也可以使用.SDcols
,这样就不需要拆分数据了。如果 age,sex,geo\time
是唯一的,以下将起作用:
dt0[, as.list(na.spline(unlist(.SD), na.rm=FALSE)), by = `age,sex,geo\time`, .SDcols = -"age,sex,geo\time"]
## age,sex,geo\time V1 V2 V3 V4 V5
## 1: TOTAL,F,AD 32832 37408 38252 38252 40296
## 2: TOTAL,F,AL 1409931 1409931 1409931 1409931 1409931
## 3: TOTAL,F,AM 1692440 1688458 1684000 1679066 1673656
## 4: TOTAL,F,AT 4351253 4328238 4309977 4296293 4285442
## 5: TOTAL,F,AZ 4755163 4707690 4651601 4594023 4542083
使用矩阵。在 matrix
上使用矩阵运算并不慢:
mat <- t(as.matrix(dt0[,-1]))
colnames(mat) <- dt0[[1]]
mat[] <- na.spline(mat,na.rm=FALSE)
这给出了
TOTAL,F,AD TOTAL,F,AL TOTAL,F,AM TOTAL,F,AT TOTAL,F,AZ
2014 32832 1409931 1692440 4351253 4755163
2013 37408 1409931 1688458 4328238 4707690
2012 38252 1409931 1684000 4309977 4651601
2011 38252 1409931 1679066 4296293 4594023
2010 40296 1409931 1673656 4285442 4542083
使用 data.table. 如果您想使用 data.table
,请执行
mat <- t(as.matrix(dt0[,-1]))
colnames(mat) <- dt0[[1]]
DT <- data.table(mat,keep.rownames=TRUE)
DT[,(vn):=lapply(.SD,na.spline,na.rm=FALSE),.SDcols=vn]
通过引用更新 DT
,给出
rn TOTAL,F,AD TOTAL,F,AL TOTAL,F,AM TOTAL,F,AT TOTAL,F,AZ
1: 2014 32832 1409931 1692440 4351253 4755163
2: 2013 37408 1409931 1688458 4328238 4707690
3: 2012 38252 1409931 1684000 4309977 4651601
4: 2011 38252 1409931 1679066 4296293 4594023
5: 2010 40296 1409931 1673656 4285442 4542083
基准测试:
mat <- t(as.matrix(dt0[,-1]))
colnames(mat) <- dt0[[1]]
DT <- data.table(mat,keep.rownames=TRUE)
vn <- names(DT)[-1]
tvn <- names(dt0)[-1]
require(microbenchmark)
microbenchmark(
transp = dt0[,as.list(na.spline(unlist(.SD), na.rm=FALSE)),by=1:nrow(dt0),.SDcols=tvn],
lapply = DT[,lapply(.SD,na.spline,na.rm=FALSE),.SDcols=vn],
apply = apply(mat,2,na.spline,na.rm=FALSE),
fun = na.spline(mat,na.rm=FALSE),
times=10)
结果:
Unit: milliseconds
expr min lq mean median uq max neval
transp 4.666934 4.734891 4.850268 4.787690 4.897202 5.259957 10
lapply 3.923823 4.010356 4.327646 4.039445 4.049957 6.976446 10
apply 2.505556 2.525601 2.578890 2.585978 2.592090 2.758801 10
fun 1.945290 1.994178 2.063063 2.068490 2.085112 2.272846 10
"transp" 结果显示@shadow 解决方案的时间安排,它保留了 OP 的格式。由于 na.spline
的工作原理,这里不需要 apply
。
我正在尝试准备一些从欧盟统计局检索到的人口统计数据以供进一步处理,其中包括用相应的近似数据替换任何缺失的数据。
起初我只使用 data.frames,但后来我确信 data.tables 可能比常规 data.frames 有一些优势,所以我迁移到 data.tables。
我在这样做时观察到的一件事是,将 "na.spline" 与 "apply" 结合使用与 "na.spline" 作为 data.table 的一部分时会得到不同的结果。
#1源数据
(dt0 <- data.table(
"age,sex,geo\time" = c("TOTAL,F,AD", "TOTAL,F,AL", "TOTAL,F,AM", "TOTAL,F,AT", "TOTAL,F,AZ"),
"2014" = c(NA, NA, NA, 4351253, NA),
"2013" = c(37408, NA, NA, 4328238, 4707690),
"2012" = c(38252, NA, 1684000, 4309977, 4651601),
"2011" = c(38252, 1409931, 1679066, 4296293, 4594023),
"2010" = c(40296, NA, 1673656, 4285442, 4542083)
))
生成
age,sex,geo\time 2014 2013 2012 2011 2010
1: TOTAL,F,AD NA 37408 38252 38252 40296
2: TOTAL,F,AL NA NA NA 1409931 NA
3: TOTAL,F,AM NA NA 1684000 1679066 1673656
4: TOTAL,F,AT 4351253 4328238 4309977 4296293 4285442
5: TOTAL,F,AZ NA 4707690 4651601 4594023 4542083
分成"row headings"...
(dt0a <- dt0[, 1, with=FALSE])
(cn0a <- colnames(dt0a))
...和人口数据...
(dt0b <- dt0[, 2:ncol(dt0), with=FALSE])
(cn0ba <- colnames(dt0b))
#2 将 NAs 替换为 "na.spline" & "apply"
(dt1b <- data.table(t(apply(dt0b, 1, na.spline, na.rm=FALSE))))
(setnames(dt1b, cn0b))
(dt1 <- cbind(dt0a, dt1b))
这导致...
age,sex,geo\time 2014 2013 2012 2011 2010
1: TOTAL,F,AD 32832 37408 38252 38252 40296
2: TOTAL,F,AL 1409931 1409931 1409931 1409931 1409931
3: TOTAL,F,AM 1692440 1688458 1684000 1679066 1673656
4: TOTAL,F,AT 4351253 4328238 4309977 4296293 4285442
5: TOTAL,F,AZ 4755163 4707690 4651601 4594023 4542083
#3 在 "data.table"
内替换 NAs(dt2b <- dt0b[,lapply(.SD, na.spline, na.rm=FALSE)])
(dt2 <- cbind(dt0a, dt2b))
瞧瞧...
age,sex,geo\time 2014 2013 2012 2011 2010
1: TOTAL,F,AD 4351253 37408 38252.0 38252 40296.0
2: TOTAL,F,AL 4351253 1993097 -611513.8 1409931 -629363.2
3: TOTAL,F,AM 4351253 3423374 1684000.0 1679066 1673656.0
4: TOTAL,F,AT 4351253 4328238 4309977.0 4296293 4285442.0
5: TOTAL,F,AZ 4351253 4707690 4651601.0 4594023 4542083.0
#4 比较结果
(identical(dt1, dt2))
考虑到上述情况并不令人意外...
[1] FALSE
(用方法 #2 计算的替代 NAs 的值是我感兴趣的值,仅通过方法 #3 生成)。
追求 "data.table" 路线(方法 #3)的原因之一是性能(正如在各种帖子中指出的那样,当使用 "apply" 时,矩阵运算正在执行,这比仅促进 "data.table" 的相应方法花费的时间要长得多)。
作为 RI 的新手,我想我做了一些根本性的错误,唯一的问题是,我一点也不知道这可能是什么。
非常感谢能为我指明正确方向的任何帮助!
-Sil68
您在 apply
版本中进行行向运算,在 data.table
版本中进行列向运算。如果设置 by = 1:nrow(dt)
,则可以在 data.table
中进行按行操作。
dt2b <- dt0b[, as.list(na.spline(unlist(.SD), na.rm=FALSE)), by = 1:nrow(dt0b)]
也可以使用.SDcols
,这样就不需要拆分数据了。如果 age,sex,geo\time
是唯一的,以下将起作用:
dt0[, as.list(na.spline(unlist(.SD), na.rm=FALSE)), by = `age,sex,geo\time`, .SDcols = -"age,sex,geo\time"]
## age,sex,geo\time V1 V2 V3 V4 V5
## 1: TOTAL,F,AD 32832 37408 38252 38252 40296
## 2: TOTAL,F,AL 1409931 1409931 1409931 1409931 1409931
## 3: TOTAL,F,AM 1692440 1688458 1684000 1679066 1673656
## 4: TOTAL,F,AT 4351253 4328238 4309977 4296293 4285442
## 5: TOTAL,F,AZ 4755163 4707690 4651601 4594023 4542083
使用矩阵。在 matrix
上使用矩阵运算并不慢:
mat <- t(as.matrix(dt0[,-1]))
colnames(mat) <- dt0[[1]]
mat[] <- na.spline(mat,na.rm=FALSE)
这给出了
TOTAL,F,AD TOTAL,F,AL TOTAL,F,AM TOTAL,F,AT TOTAL,F,AZ
2014 32832 1409931 1692440 4351253 4755163
2013 37408 1409931 1688458 4328238 4707690
2012 38252 1409931 1684000 4309977 4651601
2011 38252 1409931 1679066 4296293 4594023
2010 40296 1409931 1673656 4285442 4542083
使用 data.table. 如果您想使用 data.table
,请执行
mat <- t(as.matrix(dt0[,-1]))
colnames(mat) <- dt0[[1]]
DT <- data.table(mat,keep.rownames=TRUE)
DT[,(vn):=lapply(.SD,na.spline,na.rm=FALSE),.SDcols=vn]
通过引用更新 DT
,给出
rn TOTAL,F,AD TOTAL,F,AL TOTAL,F,AM TOTAL,F,AT TOTAL,F,AZ
1: 2014 32832 1409931 1692440 4351253 4755163
2: 2013 37408 1409931 1688458 4328238 4707690
3: 2012 38252 1409931 1684000 4309977 4651601
4: 2011 38252 1409931 1679066 4296293 4594023
5: 2010 40296 1409931 1673656 4285442 4542083
基准测试:
mat <- t(as.matrix(dt0[,-1]))
colnames(mat) <- dt0[[1]]
DT <- data.table(mat,keep.rownames=TRUE)
vn <- names(DT)[-1]
tvn <- names(dt0)[-1]
require(microbenchmark)
microbenchmark(
transp = dt0[,as.list(na.spline(unlist(.SD), na.rm=FALSE)),by=1:nrow(dt0),.SDcols=tvn],
lapply = DT[,lapply(.SD,na.spline,na.rm=FALSE),.SDcols=vn],
apply = apply(mat,2,na.spline,na.rm=FALSE),
fun = na.spline(mat,na.rm=FALSE),
times=10)
结果:
Unit: milliseconds
expr min lq mean median uq max neval
transp 4.666934 4.734891 4.850268 4.787690 4.897202 5.259957 10
lapply 3.923823 4.010356 4.327646 4.039445 4.049957 6.976446 10
apply 2.505556 2.525601 2.578890 2.585978 2.592090 2.758801 10
fun 1.945290 1.994178 2.063063 2.068490 2.085112 2.272846 10
"transp" 结果显示@shadow 解决方案的时间安排,它保留了 OP 的格式。由于 na.spline
的工作原理,这里不需要 apply
。