如何在data.table::fwrite中设置sep2参数实现列内值无分隔输出
问题说明
调用data.table::fwrite写入数据时,需要实现list类型列的内部值之间无分隔符,使用如下示例代码时触发报错:
library("data.table") geno <- data.table( IID = 1:10, SNP = lapply(1:10, function(i) sample(0:2, 10, replace = TRUE)) ) fwrite(geno, "Geno.txt", col.names = FALSE, sep = " ", sep2 = c("","",""))
报错信息如下:
Error in fwrite(geno, "Geno.txt", col.names = FALSE, row.names = FALSE, : is.character(sep2) && length(sep2) == 3L && nchar(sep2[2L]) == .... is not TRUE
期望输出格式为每行两列,第一列为IID值,第二列为SNP列所有内部值拼接成的无分隔字符串,两列之间用空格分隔,且不需要提前手动修改原始数据集折叠列值:
1 2221210202 2 0020010221 3 1010022212 4 0120121221 5 1212211202 6 2100002010 7 1110011210 8 1212012121 9 2221121021 10 1122220101
报错原因
fwrite的sep2参数针对list类型列设计,固定要求为长度3的字符向量,其中第二个元素(list列内部元素的分隔符)字符长度必须≥1,传入空字符串会直接触发参数校验报错,无法通过设置sep2直接实现list列内部无分隔符的效果。
解决方案
推荐使用临时列转换的方式实现,全程不会修改原始geno对象,不需要提前折叠保存列值,性能优异:
fwrite( # 仅在写入时临时拼接SNP列,不改动原数据 x = geno[, .(IID, SNP = vapply(SNP, paste, collapse = "", FUN.VALUE = character(1)))], file = "Geno.txt", col.names = FALSE, sep = " " )
vapply遍历SNP列的每个list元素,直接拼接为无分隔的字符串,仅在写入的临时data.table中生效,原始geno的SNP列仍保留list格式- 该方法无外部依赖,跨Windows、macOS、Linux系统通用,即使是十万到百万行规模的数据集,拼接和写入速度都非常快
如果不想做R层面的列转换,也可以使用特殊分隔符+写入后替换的方案,适合超大规模数据集场景:
# 选用普通文本数据几乎不可能出现的控制符\x01作为list列内部分隔符 fwrite( geno, file = "Geno.txt.tmp", col.names = FALSE, sep = " ", sep2 = c("", "\x01", "") ) # 调用系统命令替换掉临时文件中的特殊分隔符,输出最终文件 if (.Platform$OS.type == "unix") { system("sed 's/\\x01//g' Geno.txt.tmp > Geno.txt") } else { system("powershell -Command \"Get-Content Geno.txt.tmp | ForEach-Object { $_ -replace [char]1, '' } | Set-Content Geno.txt\"") } # 清理临时文件 unlink("Geno.txt.tmp")
内容的提问来源于stack exchange,提问作者Fernando Brito Lopes
相关产品推荐
相关产品推荐

