我使用下面的(伪)代码在R中导入巨大的CSV文件,当文件中只有相当小的一部分数据需要处理/导入,其他行应该被忽略时。我不把数据放在内存中,而是放在程序创建的SQLite数据库中。
library(sqldf)
suppressWarnings(read.csv.sql(
file = input_file_path,
sql = "
create table mytable as
select
. . .
from
file
where
. . .
",
header = FALSE,
sep = "|",
eol = "\n",
`field.types` = list( . . . )
dbname = sqlite_db_path,
drv = "SQLite"
))
如果我正确理解了read.csv.sql
的文档,那么上面的CREATE TABLE
语句中的WHERE
子句可以保证只有满足WHERE子句条件的行才会被插入到创建的表mytable
中。昨天晚上在一个测试中,我发现我的程序有些奇怪的行为。2我不得不导入一个大的CSV文件(超过100 000 000行),但只有一组10 000行是目标,所有其他行都必须忽略。上面的程序完成了这项工作,最后,上面的代码中所指示的创建的表mytable
,只有10000行,这证明考虑了WHERE
子句中的条件。但是,当我检查创建的SQLite数据库的大小时,它异常巨大(超过25 GB)。这不可能是10000行的大小。
因此,我很困惑。在导入过程中发生了什么?为什么SQLite数据库文件变得如此庞大,以至于只在mytable
中插入了10000行,而其他的一切都被忽略了?这是正常的行为还是我没有正确使用read.csV.sql
?
2条答案
按热度按时间wlwcrazw1#
编辑:这是对@G.Grothendieck在上面评论部分提出的建议的详细说明。
我没有使用
read.csv.sql
的经验,但是你可能想看看从shell命令导入输出。这样,你预处理csv,并且只导入结果。例如,
data.table::fread(cmd = 'findstr "^[^#]" test.csv', sep = "\n", header = FALSE)
导入csvtest.csv
中所有不以#
-字符开头的行。因此,它导入(windows)命令的输出:
findstr "^[^#]" test.csv
到一个data.table,使用data.table::fread()
的所有功能和它的参数。这也可以在 * nix环境下工作,但是你必须使用适当的shell命令(比如grep
)。注意,这种方法可能工作得很好(而且很快!),但是它不可能在多个操作系统上交换代码。
h9a6wy2h2#
感谢@G. Grothendieck的澄清:
它首先使用dbWriteTable将文件写入数据库。然后对该文件进行操作。您可以考虑使用grep/findstr/xsv将感兴趣的行提取出来,并将其直接导入R. read.table(pipe(“grep...”),sep =“,”)或Windows findstr或xsv或其他csv实用程序,然后使用该实用程序代替grep。