[英]Is there a more efficient way to replace NULL with NA in a list?
我经常遇到这样的结构数据:
employees <- list(
list(id = 1,
dept = "IT",
age = 29,
sportsteam = "softball"),
list(id = 2,
dept = "IT",
age = 30,
sportsteam = NULL),
list(id = 3,
dept = "IT",
age = 29,
sportsteam = "hockey"),
list(id = 4,
dept = NULL,
age = 29,
sportsteam = "softball"))
在许多情况下,此类列表可能长达数千万个项目,因此内存问题和效率始终是一个问题。
我想将列表转换为数据帧,但如果我运行:
library(data.table)
employee.df <- rbindlist(employees)
由于NULL值,我得到错误。 我的正常策略是使用如下函数:
nullToNA <- function(x) {
x[sapply(x, is.null)] <- NA
return(x)
}
然后:
employees <- lapply(employees, nullToNA)
employee.df <- rbindlist(employees)
返回
id dept age sportsteam
1: 1 IT 29 softball
2: 2 IT 30 NA
3: 3 IT 29 hockey
4: 4 NA 29 softball
但是,当应用于1000万个案例时,nullToNA函数非常慢,因此如果有更有效的方法则会很好。
有一点似乎减慢了它的进程,is.null函数一次只能应用于一个项目(与可以一次扫描完整列表的is.na不同)。
有关如何在大型数据集上有效执行此操作的任何建议?
R中的许多效率问题通过首先将原始数据更改为使得后续过程尽可能快速和简单的形式来解决。 通常,这是矩阵形式。
如果你把所有的数据一起rbind
,你nullToNA
功能不再拥有搜索虽然嵌套列表,因此sapply
用于其目的(虽然看一个矩阵)更有效。 从理论上讲,这应该会使流程更快。
顺便问一下好问题。
> dat <- do.call(rbind, lapply(employees, rbind))
> dat
id dept age sportsteam
[1,] 1 "IT" 29 "softball"
[2,] 2 "IT" 30 NULL
[3,] 3 "IT" 29 "hockey"
[4,] 4 NULL 29 "softball"
> nullToNA(dat)
id dept age sportsteam
[1,] 1 "IT" 29 "softball"
[2,] 2 "IT" 30 NA
[3,] 3 "IT" 29 "hockey"
[4,] 4 NA 29 "softball"
在使用rbind
对数据帧进行梳理后,两步法会创建一个数据帧:
employee.df<-data.frame(do.call("rbind",employees))
现在替换NULL,我使用“NULL”,因为R在加载数据时没有放置NULL,并且在加载数据时将其作为字符读取。
employee.df.withNA <- sapply(employee.df, function(x) ifelse(x == "NULL", NA, x))
我发现更易于阅读的整合解决方案是编写一个对单个元素起作用的函数,并将其映射到所有NULL上。
我将使用@ rich-scriven的rbind和lapply方法创建一个矩阵,然后将其转换为数据帧。
library(magrittr)
dat <- do.call(rbind, lapply(employees, rbind)) %>%
as.data.frame()
dat
#> id dept age sportsteam
#> 1 1 IT 29 softball
#> 2 2 IT 30 NULL
#> 3 3 IT 29 hockey
#> 4 4 NULL 29 softball
然后我们可以在2的深度使用purrr::modify_depth()
来应用replace_x()
replace_x <- function(x, replacement = NA_character_) {
if (length(x) == 0 || length(x[[1]]) == 0) {
replacement
} else {
x
}
}
out <- dat %>%
purrr::modify_depth(2, replace_x)
out
#> id dept age sportsteam
#> 1 1 IT 29 softball
#> 2 2 IT 30 NA
#> 3 3 IT 29 hockey
#> 4 4 NA 29 softball
所有这些解决方案(我认为)都隐藏了这样一个事实,即数据表仍然是列表丢失而不是向量列表(我在应用程序中没有注意到,直到它开始在:=
期间抛出意外错误)。 尝试这个:
data.table(t(sapply(employees, function(x) unlist(lapply(x, function(x) ifelse(is.null(x),NA,x))))))
我相信它工作正常,但我不确定它是否会受到缓慢的影响并且可以进一步优化。
我经常发现do.call()
函数难以阅读。 我每天使用的解决方案(MySQL输出包含"NULL"
字符值):
NULL2NA <- function(df) {
df[, 1:length(df)][df[, 1:length(df)] == 'NULL'] <- NA
return(df)
}
但是对于所有解决方案:请记住,如果没有na.rm = TRUE
, NA
不能用于计算,但是你可以使用NULL
。 NaN
给出了同样的问题。 例如:
> mean(c(1, 2, 3))
2
> mean(c(1, 2, NA, 3))
NA
> mean(c(1, 2, NULL, 3))
2
> mean(c(1, 2, NaN, 3))
NaN
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.