【问题标题】:Replace NULL with NA in r data.table with lists用列表替换 r data.table 中的 NULL 和 NA
【发布时间】:2021-10-22 10:10:35
【问题描述】:

我有一个从 MongoDb 数据库作为 data.table 导入的数据集,其中一些列被格式化为列表并包含一些 NULL 值。 NULL 值导致我在尝试通过引用第一个表来填充另一个 data.table 中的列时出现一些问题,因为目标列不是列表格式(因此不能有 NULL 值)。

我在下面找到了一个解决方案,目前效果很好,但是我的测试数据集只有 6 条记录,我想知道在处理更大的数据集时这是否会遇到困难,或者是否有更有效的方法来做到这一点(在数据表)?

以下是一些示例数据:

library(data.table)
dt <- data.table(id = c(1,2,3), age = list(12, NULL, 15), sex = list("F", "M", NULL))

这是我应用的解决方案:

# Function to change NULL to NA in a data.table with lists:
null2na <- function(dtcol){
  nowna = lapply(dtcol, function(x) ifelse(is.null(x), NA_real_, x))
  return(nowna)
}

# Apply the function to the data.table to replace NULLs with NAs:
dt[, c(names(dt)) := lapply(.SD, null2na), .SDcols = names(dt)]

【问题讨论】:

    标签: r null data.table na


    【解决方案1】:

    我的玩具示例太小,无法比较时间,但结合了@B 建议的两种解决方案。 Christian Kamgang 和@Ronak Shah 很适合我:

    # Function to replace NULL with NA in lists:
    null2na <- function(dtcol){
      fullcol = replace(dtcol, lengths(dtcol) == 0L, NA)
      return(fullcol)
    
    # Apply function to dataset:
    dt[, names(dt) := lapply(.SD, null2na)]
    
    

    我发现这种方法有两点优势(感谢两位受访者的建议):

    1. 避免使用基数 r ifelsedplyr::if_elsedata.table::fifelse; base r ifelse 将所有列转换为列表,除非您事先指定它们,并且 ifelse 的 dplyr 和 data.table 版本,虽然它们尊重原始列类在这种情况下不起作用,因为 NA 被解释为不同从列表中的其他值输入类型。

    2. 函数lengths(dtcol) == 0L 的使用专门针对为空的列表元素,不对其他列或值做任何事情。这意味着没有必要事先指定作为列表的列的子集,因为它本质上只处理那些。

    3. 我使用 replace() 而不是在函数中设置子集 dtcol,因为我认为对于更大的数据集,前者可能会稍微快一些(但尚未测试)。

    【讨论】:

      【解决方案2】:

      这里有另一种解决问题的方法:

      cols <- names(dt)[sapply(dt, is.list)]   # get names of list columns 
      
      dt[, (cols) := lapply(.SD, function(x) replace(x, lengths(x)==0L, NA)), .SDcols=cols]
      

      【讨论】:

      • 我之前没遇到过lengths,这个很有用。我在原始解决方案中发现的一个问题是将所有列转换为列表 - 而我需要它们保持原始格式(无论是列表还是向量)以推回 MongoDb。我尝试过的所有ifelse 类型的解决方案都会导致格式问题,这两种解决方案都建议避免这种情况。我发现我可以结合您的两个解决方案,然后甚至不需要确定哪些列是列表,因为lengths 已经这样做了。另外,也许我在使用NA_real_ 时过于谨慎。
      【解决方案3】:

      您可以使用lengths 函数保存一个lapply 调用。

      library(data.table)
      
      null2na <- function(dtcol){
        dtcol[lengths(dtcol) == 0] <- NA
        return(dtcol)
      }
      
      dt[, names(dt) := lapply(.SD, null2na)]
      dt
      #   id age sex
      #1:  1  12   F
      #2:  2  NA   M
      #3:  3  15  NA
      

      agesex 列仍然是列表。如果您希望它们作为简单的向量,请从函数中返回 unlist(dtcol)

      【讨论】:

        猜你喜欢
        • 2020-07-01
        • 2019-07-22
        • 2020-09-13
        • 1970-01-01
        • 2016-03-11
        • 2017-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多