这里可能有几件事情:
无论你在这里写了"0",读取函数(fread)都是根据文件的一部分来推断数据类型的。这种情况很常见(readr也是如此),并且是可以控制的(使用colClasses=参数)。
这可能是你问题中独特的(而不是真实数据中的),但是调用write.csv时会隐式地将字面上的NA字母放入文件中(不要与你有字面字符串的“NA”相混淆)。即使你使用colClasses=覆盖,这可能会导致问题。
你可能已经知道这点,但是由于fread推断这些列的数据类型为整型,因此它们不能包含空字符串:一旦确定为数字列,任何非数字的内容都会被认为是NA。
让我们重新生成你的第一个csv文件以确保我们不会混淆情况。
write.csv(matrix(c("0","",NA,"NA"),ncol = 2), "MRE.csv", na="")
以下是使用magrittr
的管道运算符%>%
,仅供展示,不是必需的。
第一个示例演示了fread
的推断。第二个示例展示了我们覆盖了该行为,现在我们在每个非字面字符串"NA"
的NA
位置都有空白字符串。
fread("MRE.csv") %>% str
fread("MRE.csv", colClasses="character") %>% str
在每列的基础上也可以进行控制。这个例子中的一个问题是,fread
强制将行名所在的列命名为 V1
,与下一列相同。我认为这看起来像是一个错误,也许您可以查看 Rdatatable's issues 并可能发布一个新的问题。(我可能是错的,也许这是故意的或已知的行为。)
因此,每列覆盖似乎会停止在第一个列名的出现处。
fread("MRE.csv", colClasses=c(V1="character", V2="character")) %>% str
解决这个问题的一种方法是使用一个未命名的向量,需要与列数相同数量的类:
fread("MRE.csv", colClasses=c("character","character","character")) %>% str
另一种方法(感谢@thelatemail)是使用列表:
fread("MRE.csv", colClasses=list(character=2:3)) %>% str
顺便提一句:如果您需要将它们保留为整数/数字,则:
如果您担心它会影响后续的计算,那么您可以:
- 修复数据源,使其不提供空值;
- 过滤掉不完整的观测值(行);或者
- 修复计算以智能地处理缺失数据。
如果您担心它在报告中的显示效果,那么您使用的任何呈现报告的工具都应该有一种机制来显示 NA
值;例如,在 knitr::kable(...)
之前设置 options(knitr.kable.NA="")
将它们呈现为空字符串。
如果您担心它在您的 控制台 上的显示效果,您有两个选择:
- 通过迭代每个(预期的)列并将
NA
值更改为 ""
来干扰数据;这仅适用于 character
列,并且是不可逆的;或者
- 编写自己的
data.frame
子类,以更改在控制台上的显示方式;这样做的好处是它是非破坏性的;问题是您必须重新分类每个对象以在需要此行为的地方使用它,并且大多数(如果不是全部)输出框架的函数可能会无意中剥离或省略您输入的该类别。(您需要编写 print
的 S3 方法来执行此操作。)
fread
时添加colClasses=c(V1="character",V2="character")
,它能够工作吗? - r2evanswrite.csv
在添加显式的NA
(未引用的字符串)。MRE.csv
中的第一行数据是"1","0",NA
,第二行数据是"2","","NA"
。也许你的例子应该使用write.csv(..., na="")
? - r2evansmatrix
和write.csv
中写入的字符串是"0"
还是其他形式,真正影响结果的是读取函数对其的解释。 - r2evans