执行这些步骤的内存要求最低的方法是什么?

时间:2011-09-28 10:51:20

标签: r memory

我发布了a question yesterday,得到了专家的精彩回应。但是,我现在面临另一个问题,我发现我的实际数据无法完成作业,因为我的起始文件(df1)太大了。我想知道是否有更快的方法来做同样的工作而不使用adply或for循环?

我原来的问题如下:

第1步:我有一个简化的数据框:

df1 = data.frame (B=c(1,0,1), C=c(1,1,0)
  , D=c(1,0,1), E=c(1,1,0), F=c(0,0,1)
  , G=c(0,1,0), H=c(0,0,1), I=c(0,1,0))

  B C D E F G H I
1 1 1 1 1 0 0 0 0
2 0 1 0 1 0 1 0 1
3 1 0 1 0 1 0 1 0

第2步:我想做行减法,即(row1 - row2),(row1-row3)和(row2-row3)

row1-row2    1  0    1  0    0  -1   0  -1
row1-row3    0  1    0  1   -1   0  -1   0
row2-row3   -1  1   -1  1   -1   1  -1   1

步骤3:将所有-1替换为0

row1-row2   1   0   1   0   0   0   0   0
row1-row3   0   1   0   1   0   0   0   0
row2-row3   0   1   0   1   0   1   0   1

你能不能教我如何以更少记忆要求的方式这样做?

3 个答案:

答案 0 :(得分:4)

我知道做第2步的最快方法是将df1中的索引用于您想要进行的各种成对比较。 combn()函数可用于生成所需的逐行比较集。 (使用它将是 big 数据集的速率限制步骤。)

对于我们想要形成的逐行操作的组合:

> cmb <- combn(as.numeric(rownames(df1)), 2)
> cmb
     [,1] [,2] [,3]
[1,]    1    1    2
[2,]    2    3    3

cmb行表示形成所请求输出的三行所需的df1所需的两组索引。 (列3表示预期结果中的3行。)

下一步是使用两行cmb来索引df1,并通过-在R中使用标准的矢量化操作,例如:

> (out <- df1[cmb[1,], ] - df1[cmb[2,], ])
     B C  D E  F  G  H  I
1    1 0  1 0  0 -1  0 -1
1.1  0 1  0 1 -1  0 -1  0
2   -1 1 -1 1 -1  1 -1  1

现在可以完成第3步,但我假设结果输出中只能有10-1值:

> out[out < 0] <- 0
> out
    B C D E F G H I
1   1 0 1 0 0 0 0 0
1.1 0 1 0 1 0 0 0 0
2   0 1 0 1 0 1 0 1

这与您请求的输出一致。

对于大型操作,使用矩阵执行此操作可能会更快。所以我们可以这样做:

> mat <- data.matrix(df1)
> cmb <- combn(seq_len(NROW(mat)), 2)
> cmb
     [,1] [,2] [,3]
[1,]    1    1    2
[2,]    2    3    3
> out2 <- mat[cmb[1,], ] - mat[cmb[2,], ]
> out2[out2 < 0] <- 0
> out2
     B C D E F G H I
[1,] 1 0 1 0 0 0 0 0
[2,] 0 1 0 1 0 0 0 0
[3,] 0 1 0 1 0 1 0 1

如果您需要显示的rownames,那么您可以在最后轻松生成这些:

> apply(cmb, 2, function(x) paste("row", x[1], "-row", x[2], sep = ""))
[1] "row1-row2" "row1-row3" "row2-row3"

可以用作:

> rownames(out) <- apply(cmb, 2, function(x) paste("row", x[1], "-row", x[2], sep = ""))
> out
          B C D E F G H I
row1-row2 1 0 1 0 0 0 0 0
row1-row3 0 1 0 1 0 0 0 0
row2-row3 0 1 0 1 0 1 0 1

答案 1 :(得分:3)

直接使用sqldf软件包或RSQLite可以在R外部完成所有计算,这样就不需要中间存储。我们用sqldf来说明。有关详细信息,请参阅sqldf home page

备选方案1 在此方法中请注意,我们使用dbname = tempfile(),以便它在外部数据库中执行所有计算(它会动态创建并自动删除),而不是在存储器中。

library(sqldf)
gc()
DF <- sqldf("select x.rowid x, y.rowid y,
    max(x.B - y.B, 0) B, max(x.C - y.C, 0) C, 
    max(x.D - y.D, 0) D, max(x.E - y.E, 0) E,
    max(x.F - y.F, 0) F, max(x.G - y.G, 0) G, 
    max(x.H - y.H, 0) H, max(x.I - y.I, 0) I
    from df1 x, df1 y
    where x.rowid > y.rowid", dbname = tempfile())

这只需要我们能够在工作区中存储df1DF

备选方案2 。如果即使溢出,我们也可以写出df1,删除它,执行下面的计算,然后我们只需要足够的存储来存储结果DF

read.csv.sql默认使用dbname = tempfile(),所以在这种情况下我们不需要指定它。

write.table(df1, "data.txt", sep = ",", quote = FALSE)
rm(df1)
gc()
DF <- read.csv.sql("data.txt", sql = "select
    x.rowid x, y.rowid y, 
    max(x.B - y.B, 0) B, max(x.C - y.C, 0) C, 
    max(x.D - y.D, 0) D, max(x.E - y.E, 0) E,
    max(x.F - y.F, 0) F, max(x.G - y.G, 0) G, 
    max(x.H - y.H, 0) H, max(x.I - y.I, 0) I
    from file x, file y
    where x.rowid > y.rowid")

(当然,如果真的那么大,那么你也可能无法对其进行任何后续计算。)

<强>输出即可。无论如何,两种替代方案都给出了如下所示的相同结果。 x和y显示减去了哪些输入行。

> DF
  x y B C D E F G H I
1 2 1 0 0 0 0 0 1 0 1
2 3 1 0 0 0 0 1 0 1 0
3 3 2 1 0 1 0 1 0 1 0

注意即可。虽然问题是要求优化内存而不是速度如果速度是一个问题,可以添加索引。

答案 2 :(得分:3)

由于数据是同质的,因此请使用矩阵表示。组织它,以便'行'是列,如

m <- t(as.matrix(df1))
mode(m) <- "integer"  # maybe already true?

为答案预先分配空间

n <- ncol(m) - 1
ans <- matrix(0L, nrow(m), (n+1) * n / 2)

我们希望将列1与列1:n + 1L进行比较(1L将第一个值视为整数值,而不是实数)。这是m[,1] - m[, 1:n + 1L],使用R的回收。迭代列,idxoff有助于跟踪我们要比较的列的索引,以及答案中的展示位列

off <- 0
for (i in 1:n) {
    idx <- i:n + 1L
    ans[, off + seq_along(idx)] <- m[, i] - m[, idx]
    off <- off + length(idx)
}

最后一步是

ans[ans<0L] <- 0L

除非m[,1] == 1 & m[, 1:n + 1L] == 0,否则认识到原始操作下的真值表为0可能会有额外的效率。同样,如果空间是一个严重的问题,那么数据可能表示为mode(m) <- "raw",并且算术运算被刚刚建议的比较所取代,如下所示:

m <- t(as.matrix(df1))
mode(m) <- "raw"

off <- 0
x0 <- as.raw(0); x1 <- as.raw(1)
ans <- matrix(raw(), nrow(m), (n+1) * n / 2)
for (i in 1:n) {
    idx <- i:n + 1L
    updt <- which((m[, i] == x1) & (m[, idx] == x0))
    ans[off + updt] <- x1
    off <- off + length(idx) * nrow(ans)
}