【问题标题】:parsing quotes out of "NA" strings从“NA”字符串中解析引号
【发布时间】:2016-04-06 15:20:21
【问题描述】:

我的数据框有一些变量包含缺失值作为字符串,如"NA"。解析包含这些列的数据帧中的所有列并将它们转换为由is.na() 等函数捕获的真实 NA 的最有效方法是什么?

我正在使用 sqldf 来查询数据库。

可重现的例子:

vect1 <- c("NA", "NA", "BANANA", "HELLO")
vect2 <- c("NA", 1, 5, "NA")
vect3 <- c(NA, NA, "NA", "NA")


df = data.frame(vect1,vect2,vect3)

【问题讨论】:

  • 最好的方法是在读取数据时处理这些问题。如果您正在使用标准工具阅读,请查看 na.strings 参数。否则this 应该有帮助,但用 NA 替换句点
  • 什么是标准工具?我正在从 sql 数据库中读取所有数据,这可能会使读取数据时难以处理这些数据
  • 好的,你具体使用的是什么函数.. 很确定他们会有一个 na.strings 参数
  • 是的,不幸的是,我认为 na.strings 在我的情况下不会起作用
  • 我使用sqldf查询数据库

标签: r sqldf


【解决方案1】:

要添加替代方案,您还可以使用 replace 代替典型的 blah[index] &lt;- NA 方法。 replace 看起来像:

df <- replace(df, df == "NA", NA)

要考虑的另一种选择是type.convert。这是 R 在读入数据以自动转换列类型时使用的函数。因此,结果与您当前的方法不同,例如,第二列被转换为数字。

df[] <- lapply(df, function(x) type.convert(as.character(x), na.strings = "NA"))
df

这是一个性能比较。样本数据来自@roland 的回答。

以下是要测试的功能:

funop <- function() {
  df[df == "NA"] <- NA
  df
}

funr <- function() {
  ind <- which(vapply(df, function(x) class(x) %in% c("character", "factor"), FUN.VALUE = TRUE))
  as.data.table(df)[, names(df)[ind] := lapply(.SD, function(x) {
    is.na(x) <- x == "NA"
    x
  }), .SDcols = ind][]
}

funam1 <- function() replace(df, df == "NA", NA)

funam2 <- function() {
  df[] <- lapply(df, function(x) type.convert(as.character(x), na.strings = "NA"))
  df
}

这是基准测试:

library(microbenchmark)
microbenchmark(funop(), funr(), funam1(), funam2(), times = 10)
# Unit: seconds
#      expr      min       lq     mean   median       uq      max neval
#   funop() 3.629832 3.750853 3.909333 3.855636 4.098086 4.248287    10
#    funr() 3.074825 3.212499 3.320430 3.279268 3.332304 3.685837    10
#  funam1() 3.714561 3.899456 4.238785 4.065496 4.280626 5.512706    10
#  funam2() 1.391315 1.455366 1.623267 1.566486 1.606694 2.253258    10

replace 与@roland 的方法相同,与@jgozal 的方法相同。但是,type.convert 方法会导致不同的列类型。

all.equal(funop(), setDF(funr()))
all.equal(funop(), funam())

str(funop())
# 'data.frame': 10000000 obs. of  3 variables:
#  $ vect1: Factor w/ 3 levels "BANANA","HELLO",..: 2 2 NA 2 1 1 1 NA 1 1 ...
#  $ vect2: Factor w/ 3 levels "1","5","NA": NA 2 1 NA 1 NA NA 1 NA 2 ...
#  $ vect3: Factor w/ 1 level "NA": NA NA NA NA NA NA NA NA NA NA ...

str(funam2())
# 'data.frame': 10000000 obs. of  3 variables:
#  $ vect1: Factor w/ 2 levels "BANANA","HELLO": 2 2 NA 2 1 1 1 NA 1 1 ...
#  $ vect2: int  NA 5 1 NA 1 NA NA 1 NA 5 ...
#  $ vect3: logi  NA NA NA NA NA NA ...

【讨论】:

    【解决方案2】:

    我从this 问题中找到了这种好方法:

    所以对于这种特殊情况,它只是:

    df[df=="NA"]<-NA   
    

    500 万行和约 250 个变量只用了大约 30 秒

    【讨论】:

    • 您可以更快地做到这一点,例如,使用包 data.table。但是您没有提供df 的可重现示例,这使我无法编写和测试/基准测试答案。
    • 添加了可重现的示例
    【解决方案3】:

    这稍微快一点:

    set.seed(42)
    df <- do.call(data.frame, lapply(df, sample, size = 1e7, replace = TRUE))
    df2 <- df
    system.time(df[df=="NA"]<-NA )
    # user      system     elapsed 
    #3.601       0.378       3.984 
    
    library(data.table)
    setDT(df2)
    system.time({
      #find character and factor columns
      ind <- which(vapply(df2, function(x) class(x) %in% c("character", "factor"), FUN.VALUE = TRUE))
      #assign by reference
      df2[, names(df2)[ind] := lapply(.SD, function(x) {
      is.na(x) <- x == "NA"
      x
    }), .SDcols = ind]
    })
    # user      system     elapsed 
    #2.484       0.190       2.676 
    all.equal(df, setDF(df2))
    #[1] TRUE
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-13
      • 2022-01-19
      • 2021-10-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      相关资源
      最近更新 更多