R中大文件的操作

Ore*_*e M 8 sql r data.table

我有15个数据文件,每个大约4.5GB.每个文件是大约17,000个客户的数月数据.总之,这些数据代表了15个月内17,000名客户的信息.我想重新格式化这些数据,而不是每个表示一个月的15个文件,我为每个客户及其所有数据提供了17,000个文件.我写了一个脚本来做到这一点:

#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
    }
  }
 }
Run Code Online (Sandbox Code Playgroud)

该脚本有效(至少,我很确定).问题是它非常慢.按照我要的速度,它需要一周或更长的时间才能完成,我没有那个时间.你们中的任何一个人在R中做得更好,更快捷吗?我应该尝试在像SQL这样的事情吗?我以前从未真正使用过SQL; 你们中的任何人都可以告诉我这样的事情会怎样吗?任何输入都非常感谢.

jan*_*cki 16

作为@Dominic Comtois,我也建议使用SQL.
R可以处理相当大的数据 - 有20亿行的好基准比python好 - 但由于R主要在内存中运行,你需要有一台好的机器才能使它工作.您的情况仍然不需要一次加载超过4.5GB的文件,因此它应该在个人计算机上可行,请参见快速非数据库解决方案的第二种方法.
您可以使用R将数据加载到SQL数据库,稍后从数据库中查询它们.如果您不了解SQL,可能需要使用一些简单的数据库.R的最简单方法是使用RSQLite(不幸的是,自v1.1以来它不再是精简版).您无需安装或管理任何外部依赖项.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)
Run Code Online (Sandbox Code Playgroud)

就这样.您使用SQL而不必通常需要做很多通常与数据库相关的开销.

如果您更喜欢使用帖子中的方法,我认为您可以write.csv通过在data.table中进行聚合时按组进行大幅加速.

library(data.table)
monthfiles <- c("month1","month2") # ...
# write data
for(monthfile in monthfiles){
  fread(monthfile)[, write.csv(.SD,file=paste0(CustomerID,".csv"), append=TRUE), by=CustomerID]
  cat("data for",monthfile,"written to csv\n")
}
Run Code Online (Sandbox Code Playgroud)

因此,您可以在data.table中使用快速唯一,并在分组时执行子集,这也是超快的.以下是该方法的工作示例.

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

更新2016年12月5日:
从data.table开始1.9.8+你可以替换write.csv使用fwrite的,例如这个答案.


Dom*_*ois 5

我想你已经有了答案.但要加强它,请参阅官方文件

R数据导入导出

那说明

通常,像R这样的统计系统并不特别适合于操纵大规模数据.其他一些系统比R更好,本手册的部分内容是建议不要在R中复制功能,而是让另一个系统完成工作!(例如,Therneau&Grambsch(2000)评论说,他们更喜欢在SAS中进行数据操作,然后在S中使用包生存进行分析.)数据库操作系统通常非常适合操作和提取数据:几个与DBMS交互的包在这里讨论.

因此,海量数据的存储显然不是R的主要优势,但它为几个专门用于此的工具提供了接口.在我自己的工作中,轻量级的SQLite解决方案就足够了,即使它在某种程度上是一个偏好的问题.搜索"使用SQLite的缺点",你可能找不到太多劝阻你.

您应该会发现SQLite的文档非常流畅.如果你有足够的编程经验,那么做一两个教程应该会让你在SQL前面快速进行.我没有在代码中看到任何过于复杂的内容,因此最常见的基本查询(如CREATE TABLE,SELECT ... WHERE)可能会满足您的所有需求.

编辑

使用DBMS的另一个优点是我没有提到,如果有人说,你可以views让其他数据组织容易访问schemas.通过创建视图,您可以返回"按月显示",而无需重写任何表,也不必复制任何数据.