R中表的内存问题

时间:2018-02-06 14:59:16

标签: r memory count

我需要从 R中的一系列大型向量(实际上是数据帧列,但我认为这不相关)中创建频率表。当我运行时cache.set,内存使用量稳步攀升,直到系统耗尽内存, R 崩溃并重新启动(16GB)。矢量本身非常大(5.9m obs),但显然远不及16gb - 我不太明白为什么table()使用了这么多的记忆。我从bigtable包中尝试过table(),从plyr尝试bigtabulate(),但没有区别。我写了自己的小功能(下图),但速度非常慢。有没有一种不同的做法比我粗略的尝试更快但没有使用count()table()那么多的内存?

count()

2 个答案:

答案 0 :(得分:0)

我创建了一个示例向量并运行table。这代表标准

set.seed(1)
# this works with 16 GB
V <- sample(1:100, 6e6, replace=TRUE)
table(V)

# V
    # 1     2     3     4     5     6     7     8     9    10    11    12    13 
# 59851 60360 60662 60097 59978 59894 60252 60106 60075 59636 59926 60069 60007 
   # 14    15    16    17    18    19    20    21    22    23    24    25    26 
# 59576 60052 59912 59804 59861 59737 59903 60055 59877 60259 60090 59856 60660 
   # 27    28    29    30    31    32    33    34    35    36    37    38    39 
# 60157 60137 59653 60323 59649 60017 59616 60060 60004 60116 60157 60360 59860 
   # 40    41    42    43    44    45    46    47    48    49    50    51    52 
# 59957 59892 59813 59986 60009 60457 59875 59464 59806 60302 60002 59938 60079 
   # 53    54    55    56    57    58    59    60    61    62    63    64    65 
# 59876 59940 60059 60245 59949 60089 59942 60001 59973 60661 60157 60210 60189 
   # 66    67    68    69    70    71    72    73    74    75    76    77    78 
# 59770 59948 60333 59601 60353 59344 60089 60316 59529 59617 59694 59969 59790 
   # 79    80    81    82    83    84    85    86    87    88    89    90    91 
# 59743 60141 59975 59990 59658 60147 60389 60472 60111 60094 60102 60050 59612 
   # 92    93    94    95    96    97    98    99   100 
# 59911 60022 60228 59780 60153 59691 60041 59992 59810 

请尝试以下操作来拆分数据并汇总列表结果

L <- split(V, rep(1:10, each=(6e6/10)))
# you could use as well:  cut(V, breaks=10)
# in place of rep(...)

Ts <- lapply(L, table)  # table of each split

# merge results
merge_tables <- function(L) {
    require(dplyr)
    DF <- do.call(rbind, lapply(L, data.frame))
    ans <- DF %>%
           group_by(Var1) %>%
           summarise(Freq = sum(Freq))
    return(ans) 
}
merge_tables(Ts)

# A tibble: 100 x 2
   # Var1    Freq
   # <fctr> <int>
 # 1 1      59851
 # 2 2      60360
 # 3 3      60662
 # 4 4      60097
 # 5 5      59978
 # 6 6      59894

答案 1 :(得分:0)

由于您正在处理data.frame,因此您可以循环使用tabulate()代替table()tabulate()通常要快得多。由于您提到自己遇到内存问题,因此可以使用简单的for循环。

以下是100列data.frame的示例,其中包含590万行。

set.seed(1)
mydf <- data.frame(replicate(100, sample(100, 59e5, TRUE, prob = (1 / 1:100)/sum(1/1:100))))

使用预期唯一值的数量创建一个空向量。在这里,我将其硬编码为100,但您可以通过不同方式有效地找到它。

x <- vector(mode = "integer", length = 100)

使用for循环和tabulate,在每次迭代时将值添加到向量中。

for (i in seq_along(mydf)) {
  a <- tabulate(mydf[[i]], nbins = 100)
  x <- x + a
}

结果如下:

x
 #  [1] 113728224  56869605  37921007  28438216  22749305  18957822  16246750  14217145  12635554  11371434
 # [11]  10336993   9476935   8754409   8127218   7580889   7108428   6688372   6318092   5988240   5685836
 # [21]   5420640   5167806   4949677   4742169   4552045   4375381   4213460   4062181   3918424   3791238
 # [31]   3667651   3554914   3444016   3343632   3248479   3157525   3073123   2993397   2914555   2843628
 # [41]   2773669   2709270   2647620   2582847   2524157   2476936   2418578   2367692   2322076   2274352
 # [51]   2229395   2187669   2148847   2107710   2068427   2030564   1996654   1962316   1927702   1894340
 # [61]   1863165   1834852   1807164   1776901   1747323   1722719   1694721   1672816   1646864   1623807
 # [71]   1602506   1579049   1556790   1535832   1517130   1495177   1476688   1457067   1437976   1421363
 # [81]   1404197   1386446   1372361   1354048   1338653   1321241   1308175   1292688   1278896   1264299
 # [91]   1249357   1237313   1222000   1210713   1198957   1186282   1172569   1161049   1148689   1136921

如果您希望将命名向量作为结果,则可以使用setNames(x, 1:100)

测试它的性能。这一次,我没有对预期的矢量长度进行硬编码:

myfun <- function(mydf) {
  maxint <- max(vapply(mydf, max, 1L))
  x <- vector(mode = "integer", length = maxint)
  for (i in seq_along(mydf)) {
    a <- tabulate(mydf[[i]], nbins = maxint)
    x <- x + a
  }
  x
}
system.time(myfun(mydf))
#    user  system elapsed 
#   1.200   0.000   1.201 

与CPak的方法进行比较,后者使用table代替。

# merge results
merge_tables <- function(L) {
  require(dplyr)
  DF <- do.call(rbind, lapply(L, data.frame))
  ans <- DF %>%
    group_by(Var1) %>%
    summarise(Freq = sum(Freq))
  return(ans) 
}

cPakFun <- function(mydf) {
  Ts <- lapply(mydf, table)  # table of each split
  merge_tables(Ts)
}
system.time(cPakFun(mydf))
#    user  system elapsed 
# 150.937   1.041 152.872