Sql R中大文件的操作

Sql R中大文件的操作,sql,r,data.table,Sql,R,Data.table,我有15个数据文件,每个大约4.5GB。每个文件是大约17000个客户的一个月的数据。总的来说,这些数据代表了15个月内17000名客户的信息。我想重新格式化这些数据,这样,每个客户及其所有数据就有17000个文件,而不是15个文件,每个文件表示一个月。为此,我编写了一个脚本: #the variable 'files' is a vector of locations of the 15 month files exists = NULL #This vector keeps track o

我有15个数据文件,每个大约4.5GB。每个文件是大约17000个客户的一个月的数据。总的来说,这些数据代表了15个月内17000名客户的信息。我想重新格式化这些数据,这样,每个客户及其所有数据就有17000个文件,而不是15个文件,每个文件表示一个月。为此,我编写了一个脚本:

#the variable 'files' is a vector of locations of the 15 month files
exists = NULL  #This vector keeps track of customers who have a file created for them
for (w in 1:15){  #for each of the 15 month files
  month = fread(files[w],select = c(2,3,6,16))  #read in the data I want
  custlist = unique(month$CustomerID) #a list of all customers in this month file
  for (i in 1:length(custlist)){ #for each customer in this month file
    curcust = custlist[i] #the current customer
    newchunk = subset(month,CustomerID == curcust) #all the data for this customer
    filename = sprintf("cust%s",curcust) #what the filename is for this customer will be, or is
    if ((curcust %in% exists) == TRUE){ #check if a file has been created for this customer. If a file has been created, open it, add to it, and read it back
      custfile = fread(strwrap(sprintf("C:/custFiles/%s.csv",filename)))#read in file
      custfile$V1 = NULL #remove an extra column the fread adds
      custfile= rbind(custfile,newchunk)#combine read in data with our new data
      write.csv(custfile,file = strwrap(sprintf("C:/custFiles/%s.csv",filename)))
    } else { #if it has not been created, write newchunk to a csv
      write.csv(newchunk,file = strwrap(sprintf("C:/custFiles/%s.csv",filename)))
      exists = rbind(exists,curcust,deparse.level = 0) #add customer to list of existing files
    }
  }
 }

这个脚本很有效(至少,我很确定)。问题是它的速度太慢了。以我现在的速度,要花一周或更长的时间才能完成,我没有时间。你们中有谁有更好更快的方法在R中实现这一点吗?我是否应该尝试在SQL之类的工具中执行此操作?我以前从未真正使用过SQL;你们谁能告诉我怎么做这样的事?非常感谢您的任何意见。

我想您已经有了答案。但为了加强这一点,请参见官方文件

这说明

一般来说,像R这样的统计系统不是特别好 适合于大规模数据的操作。其他一些系统是 在这方面比R好,本手册的部分重点是 建议不要重复R中的功能,我们可以 另一个系统做的工作!(例如Therneau&Grambsch(2000年) 评论说,他们更喜欢在SAS中进行数据操作,然后 使用S中的包生存来分析数据库操作 系统通常非常适合操作和提取数据: 这里讨论了几个与DBMS交互的包

很明显,海量数据的存储并不是R的主要优势,但它提供了一些专用工具的接口。在我自己的工作中,轻量级SQLite解决方案就足够了,即使在某种程度上这是一个偏好问题。搜索“使用SQLite的缺点”,您可能不会发现太多可以劝阻您的地方

你会发现这很容易理解。如果您有足够的编程经验,那么做一两个教程应该可以让您快速掌握SQL方面的知识。我在代码中没有看到任何过于复杂的情况,因此最常见和基本的查询,如CREATETABLE、SELECT。。。哪里可能满足您的所有需求

编辑


我没有提到的使用DBMS的另一个优点是,您可以拥有
视图
,可以方便地访问其他数据组织
模式
。通过创建视图,您可以返回到“每月可视化”,而无需重写任何表或复制任何数据。

作为@Dominic Comtois,我也建议使用SQL。
R可以处理相当大的数据——有一个20亿行的好基准,这比python要好——但因为R主要在内存中运行,所以需要一台好的机器才能使它工作。不过,您的案例不需要一次加载超过4.5GB的文件,因此在个人计算机上应该是可行的,请参阅快速非数据库解决方案的第二种方法。
您可以利用R将数据加载到SQL数据库,然后再从数据库中查询数据。 如果您不懂SQL,可能需要使用一些简单的数据库。R中最简单的方法是使用RSQLite(不幸的是,由于v1.1,它不再是lite)。您不需要安装或管理任何外部依赖项。RSQLite包包含嵌入的数据库引擎

library(RSQLite)
library(data.table)
conn <- dbConnect(dbDriver("SQLite"), dbname="mydbfile.db")
monthfiles <- c("month1","month2") # ...
# write data
for(monthfile in monthfiles){
  dbWriteTable(conn, "mytablename", fread(monthfile), append=TRUE)
  cat("data for",monthfile,"loaded to db\n")
}
# query data
df <- dbGetQuery(conn, "select * from mytablename where customerid = 1")
# when working with bigger sets of data I would recommend to do below
setDT(df)
dbDisconnect(conn)

因此,您可以利用fast unique from data.table,在分组时执行子集设置,这也是一种超快速的方法。下面是该方法的工作示例

library(data.table)
data.table(a=1:4,b=5:6)[,write.csv(.SD,file=paste0(b,".csv")),b]


更新2016-12-05:

从data.table 1.9.8+开始,您可以用
fwrite
替换
write.csv
,例如。

您真的想要17000个文件吗?R有能力在读取文件后准确有效地分离客户。好吧,我真的希望能够一次访问任何客户数据集。由于内存限制,我一次只能在R中保存一个月的文件,即我只能访问客户数据集的1/15。拥有17000个单独的文件将允许我在任何客户数据集上循环并执行操作。我想不出更好的方法来组织它。我假设这些是最细粒度的数据。根据您对未来数据的分析需求,您可以考虑通过删除冗余信息来聚合每月数据,例如,如果您只需要分析日期,则可以使用时间。因此,您可以减少数据集的行数,并将它们绑定到一个csv文件或db表中用于分析,但仍然保留所有每月文件作为历史备份。我认为这正是视图变得有趣的地方。。。它们定义了您需要查询数据的方式。通过最大化SQL部分的工作,您的R会话最终不需要太多内存。(事实上,我意识到你在谈论数据表时,是在拥有多个文件而不是一个大数据库的背景下进行的)。我也同意@DominicComtois的观点——你需要一个数据库。但是回答您最初的问题:不要
rbind
并在循环内部的内存中执行昂贵的复制操作,而是执行
fread
,然后
写入.table
带有
append=TRUE
的子集。这会快得多。
library(data.table)
data.table(a=1:4,b=5:6)[,write.csv(.SD,file=paste0(b,".csv")),b]