【问题标题】:Memory problems with table in RR中的表的内存问题
【发布时间】:2018-02-06 14:59:16
【问题描述】:

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

level_counts<-function(v){
    df<-data.frame(value=levels(v));
    df$count<-apply(df,1,function(x){
        return(length(v[which(v==x)]));
    });
    return(df);
}

【问题讨论】:

  • 你可以拆分你的data.frame,然后table(...)每个拆分迭代,然后聚合表结果
  • 您是否偶然在所有感兴趣的列上运行table(),而不是一次在每一列(向量)上运行?
  • @Cpak 谢谢,我会试试这个
  • @RolandASc 我已经检查过了,绝对不是! cur_col

标签: r memory count


【解决方案1】:

我创建了一个示例向量并运行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

【讨论】:

    【解决方案2】:

    由于您处理的是data.frame,因此您可以遍历列并使用tabulate() 而不是table()tabulate() 通常要快得多。既然你提到你遇到了内存问题,你可以只使用一个简单的for 循环。

    这是一个包含 590 万行的 100 列 data.frame 的示例。

    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 
    

    【讨论】:

      猜你喜欢
      • 2023-03-15
      • 1970-01-01
      • 2021-12-24
      • 2014-02-27
      • 2020-03-05
      • 1970-01-01
      • 1970-01-01
      • 2011-03-21
      • 2011-04-08
      相关资源
      最近更新 更多