29

如何在 R 中绘制一个非常大的数据集?

我想使用箱线图、小提琴图或类似的图。所有数据都无法放入内存。我可以逐步阅读并计算制作这些图所需的摘要吗?如果有怎么办?

4

8 回答 8

10

作为我对Dmitri answer评论的补充,一个使用ff大数据处理包计算分位数的函数:

ffquantile<-function(ffv,qs=c(0,0.25,0.5,0.75,1),...){
 stopifnot(all(qs<=1 & qs>=0))
 ffsort(ffv,...)->ffvs
 j<-(qs*(length(ffv)-1))+1
 jf<-floor(j);ceiling(j)->jc
 rowSums(matrix(ffvs[c(jf,jc)],length(qs),2))/2
}

这是一个精确的算法,所以它使用排序——因此可能需要很多时间。

于 2010-12-03T19:47:26.193 回答
8

问题是您无法将所有数据加载到内存中。因此,您可以对数据进行采样,正如@Marek 之前所指出的那样。在如此庞大的数据集上,即使只取 1% 的数据,也能得到基本相同的结果。对于小提琴图,这将为您提供一个不错的密度估计。分位数的渐进式计算是不可能的,但这应该给出一个非常好的近似值。它与@aix 给出的链接中描述的“随机方法”基本相同。

如果您无法在 R 之外对日期进行子集化,则可以使用连接与sample(). 当数据框变得太大时,我使用以下函数从文本格式的数据框中采样数据。如果您对连接进行一些操作,您可以轻松地将其转换为 socketConnection 或其他以从服务器、数据库等读取它。只需确保以正确的模式打开连接即可。

好,拿一个简单的 .csv 文件,然后下面的函数对数据的一部分 p 进行采样:

sample.df <- function(f,n=10000,split=",",p=0.1){
    con <- file(f,open="rt",)
    on.exit(close(con,type="rt"))
    y <- data.frame()
    #read header
    x <- character(0)
    while(length(x)==0){
      x <- strsplit(readLines(con,n=1),split)[[1]]
    }
    Names <- x
    #read and process data
    repeat{
      x <- tryCatch(read.table(con,nrows=n,sep=split),error = function(e) NULL )
      if(is.null(x)) {break}
      names(x) <- Names
      nn <- nrow(x)
      id <- sample(1:nn,round(nn*p))
      y <- rbind(y,x[id,])
    }
    rownames(y) <- NULL
    return(y)
}

用法示例:

#Make a file
Df <- data.frame(
  X1=1:10000,
  X2=1:10000,
  X3=rep(letters[1:10],1000)
)
write.csv(Df,file="test.txt",row.names=F,quote=F)

# n is number of lines to be read at once, p is the fraction to sample
DF2 <- sample.df("test.txt",n=1000,p=0.2)
str(DF2)

#clean up
unlink("test.txt")
于 2010-12-03T13:40:08.787 回答
4

您还应该查看 RSQLite、SQLiteDF、RODBC 和 biglm 包。对于大型数据集,将数据存储在数据库中并仅将部分提取到 R 中可能很有用。数据库还可以为您进行排序,然后在排序后的数据上计算分位数要简单得多(然后只需使用分位数进行绘图) .

还有一个 hexbin 包(生物导体),用于对非常大的数据集进行散点图等效(可能仍想使用数据样本,但适用于大样本)。

于 2010-12-03T17:55:19.327 回答
4

您可以将数据放入数据库并使用 SQL 计算分位数。见: http: //forge.mysql.com/tools/tool.php?id=149

于 2010-12-03T18:02:03.377 回答
4

箱线图只需要分位数、“晶须”极值和异常值(如果显示),这些都很容易预先计算。看一下boxplot.stats功能。

于 2010-12-03T02:56:09.687 回答
3

这是一个有趣的问题。

箱线图需要分位数。在非常大的数据集上计算分位数很棘手。

在您的情况下可能有效或无效的最简单解决方案是首先对数据进行下采样,然后生成样本图。换句话说,一次读取一堆记录,并将其中的一个子集保留在内存中(确定性或随机选择)。最后,根据保留在内存中的数据生成绘图。同样,这是否可行很大程度上取决于数据的属性。

或者,存在可以以“在线”方式经济且近似地计算分位数的算法,这意味着它们一次呈现一个观察值,并且每个观察值仅显示一次。虽然我对此类算法的经验有限,但我还没有看到任何现成的 R 实现。

以下论文简要概述了一些相关算法:Streams 上的分位数

于 2010-12-03T10:12:01.817 回答
2

您可以从可管理的数据样本中绘制图表。例如,如果您仅使用 10% 随机选择的行,则此样本上的箱线图不应与所有数据箱线图不同。

如果您的数据在某个数据库上,您可以创建一些随机标志(据我所知,几乎每个数据库引擎都有某种随机数生成器)。

第二件事是你的数据集有多大?对于箱线图,您需要两列:值变量和组变量。这个例子:

N <- 1e6
x <- rnorm(N)
b <- sapply(1:100, function(i) paste(sample(letters,40,TRUE),collapse=""))
g <- factor(sample(b,N,TRUE))
boxplot(x~g)

需要 100MB 的 RAM。如果N=1e7那时它使用 <1GB 的 RAM(现代机器仍然可以管理)。

于 2010-12-03T09:59:19.623 回答
1

也许您可以考虑disk.frame在运行绘图之前先总结数据?

于 2018-11-01T22:31:33.877 回答