fread将空值导入为NA

3
我试图导入一个包含空格的csv文件,以""读取它们。不幸的是,它们现在都被读取为 "NA"
为了更好地演示问题,我还展示了如何将NA"NA"""都映射到同一件事情(除了最后一个例子),这将防止简单的解决方法dt[is.na(dt)] <- ""的使用。
> write.csv(matrix(c("0","",NA,"NA"),ncol = 2),"MRE.csv")

打开记事本查看,它看起来像这样:
"","V1","V2"
"1","0",NA
"2","","NA"

那么阅读回来...

> fread("MRE.csv")
   V1 V1 V2
1:  1  0 NA
2:  2 NA NA

文档似乎在暗示这个,但实际上并不按照描述的那样工作。
> fread("MRE.csv",na.strings = NULL)
   V1 V1 V2
1:  1  0 NA
2:  2 NA NA

我还尝试过这个方法,将NA解读为实际上的NA,但对于空字符串问题依旧存在,因为空字符串会被解读为"NA"

> fread("MRE.csv",colClasses=c(V1="character",V2="character"))
   V1 V1   V2
1:  1  0 <NA>
2:  2 NA   NA

> fread("MRE.csv",colClasses=c(V1="character",V2="character"))[,V2]
[1] NA   "NA"

数据表版本1.11.4

R语言版本3.5.1


如果一个列的其余部分是数字或整数,那么您就不能在其中有空字符串(除非将该列强制转换为“字符”)。如果您在调用fread时添加colClasses=c(V1="character",V2="character"),它能够工作吗? - r2evans
1
它并没有。编辑后显示这个。 而且我没有那个;我把0写成了"0"。 - hedgedandlevered
你的例子中存在问题的一部分是write.csv在添加显式的NA(未引用的字符串)。MRE.csv中的第一行数据是"1","0",NA,第二行数据是"2","","NA"。也许你的例子应该使用write.csv(..., na="") - r2evans
无论您在 matrixwrite.csv 中写入的字符串是 "0" 还是其他形式,真正影响结果的是读取函数对其的解释。 - r2evans
1个回答

2
这里可能有几件事情:
  1. 无论你在这里写了"0",读取函数(fread)都是根据文件的一部分来推断数据类型的。这种情况很常见(readr也是如此),并且是可以控制的(使用colClasses=参数)。

  2. 这可能是你问题中独特的(而不是真实数据中的),但是调用write.csv时会隐式地将字面上的NA字母放入文件中(不要与你有字面字符串的“NA”相混淆)。即使你使用colClasses=覆盖,这可能会导致问题。

  3. 你可能已经知道这点,但是由于fread推断这些列的数据类型为整型,因此它们不能包含空字符串:一旦确定为数字列,任何非数字的内容都会被认为是NA。

让我们重新生成你的第一个csv文件以确保我们不会混淆情况。

write.csv(matrix(c("0","",NA,"NA"),ncol = 2), "MRE.csv", na="")

以下是使用magrittr的管道运算符%>% ,仅供展示,不是必需的。

第一个示例演示了fread的推断。第二个示例展示了我们覆盖了该行为,现在我们在每个非字面字符串"NA"NA位置都有空白字符串。

fread("MRE.csv") %>% str
# Classes 'data.table' and 'data.frame':    2 obs. of  3 variables:
#  $ V1: int  1 2
#  $ V1: int  0 NA
#  $ V2: logi  NA NA
#  - attr(*, ".internal.selfref")=<externalptr> 

fread("MRE.csv", colClasses="character") %>% str
# Classes 'data.table' and 'data.frame':    2 obs. of  3 variables:
#  $ V1: chr  "1" "2"
#  $ V1: chr  "0" ""
#  $ V2: chr  "" "NA"
#  - attr(*, ".internal.selfref")=<externalptr> 

在每列的基础上也可以进行控制。这个例子中的一个问题是,fread 强制将行名所在的列命名为 V1,与下一列相同。我认为这看起来像是一个错误,也许您可以查看 Rdatatable's issues 并可能发布一个新的问题。(我可能是错的,也许这是故意的或已知的行为。)

因此,每列覆盖似乎会停止在第一个列名的出现处。

fread("MRE.csv", colClasses=c(V1="character", V2="character")) %>% str
# Classes 'data.table' and 'data.frame':    2 obs. of  3 variables:
#  $ V1: chr  "1" "2"
#  $ V1: int  0 NA
#  $ V2: chr  "" "NA"
#  - attr(*, ".internal.selfref")=<externalptr> 

解决这个问题的一种方法是使用一个未命名的向量,需要与列数相同数量的类:

fread("MRE.csv", colClasses=c("character","character","character")) %>% str
# Classes 'data.table' and 'data.frame':    2 obs. of  3 variables:
#  $ V1: chr  "1" "2"
#  $ V1: chr  "0" ""
#  $ V2: chr  "" "NA"
#  - attr(*, ".internal.selfref")=<externalptr> 

另一种方法(感谢@thelatemail)是使用列表:

fread("MRE.csv", colClasses=list(character=2:3)) %>% str
# Classes 'data.table' and 'data.frame':    2 obs. of  3 variables:
#  $ V1: int  1 2
#  $ V1: chr  "0" ""
#  $ V2: chr  "" "NA"
#  - attr(*, ".internal.selfref")=<externalptr> 

顺便提一句:如果您需要将它们保留为整数/数字,则:

  1. 如果您担心它会影响后续的计算,那么您可以:

    1. 修复数据源,使其不提供空值;
    2. 过滤掉不完整的观测值(行);或者
    3. 修复计算以智能地处理缺失数据。
  2. 如果您担心它在报告中的显示效果,那么您使用的任何呈现报告的工具都应该有一种机制来显示 NA 值;例如,在 knitr::kable(...) 之前设置 options(knitr.kable.NA="") 将它们呈现为空字符串。

  3. 如果您担心它在您的 控制台 上的显示效果,您有两个选择:

    1. 通过迭代每个(预期的)列并将 NA 值更改为 "" 来干扰数据;这仅适用于 character 列,并且是不可逆的;或者
    2. 编写自己的 data.frame 子类,以更改在控制台上的显示方式;这样做的好处是它是非破坏性的;问题是您必须重新分类每个对象以在需要此行为的地方使用它,并且大多数(如果不是全部)输出框架的函数可能会无意中剥离或省略您输入的该类别。(您需要编写 print 的 S3 方法来执行此操作。)

1
你也可以通过在列表中按位置指定colClasses - 参见我昨天的评论 https://stackoverflow.com/questions/58178779/fread-specifying-colclasses-of-file-with-2-columns-with-same-name-using-col-a#comment102737825_58178779 - thelatemail
谢谢,已添加到回答中。 - r2evans
1
谢谢,很高兴现在能够不使用hacky的解决方法来完成它。 - hedgedandlevered
你有什么想法关于 na.strings=NULL 无法正常工作的问题吗?这是 data.table 中的一个错误吗? - hedgedandlevered
看起来是个bug。如果你查看str(fread("MRE.csv",na.strings = NULL)),你会发现它将第三列解释为逻辑值,对于""这个值是没有意义的,因此是NA。但是由于你告诉它不要尝试推断空值,那么它应该猜测第二行是字符型,因此第一行应该是空字符串。这是一个很好的可重现问题的例子;可能相关的是https://github.com/Rdatatable/data.table/issues/3439,尽管只是因为它突出了`na.strings=`的行为。 - r2evans

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接