簡體   English   中英

是否有更有效的方法在列表中用NA替換NULL?

[英]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 = TRUENA不能用於計算,但是你可以使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM