对于R OR,Python的xrange替代方法如何循环遍历大型数据集?
以下示例基于
discussion关于使用expand.grid和大数据.如你所见,它最终会出错.我想这是由于可能的组合,根据
mentioned页68.7亿:
> v1 <- c(1:8) > v2 <- c(1:8) > v3 <- c(1:8) > v4 <- c(1:8) > v5 <- c(1:8) > v6 <- c(1:8) > v7 <- c(1:8) > v8 <- c(1:8) > v9 <- c(1:8) > v10 <- c(1:8) > v11 <- c(1:8) > v12 <- c(1:8) > expand.grid(v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12) Error in rep.int(rep.int(seq_len(nx),rep.int(rep.fac,nx)),orep) : invalid 'times' value In addition: Warning message: In rep.int(rep.int(seq_len(nx),orep) : NAs introduced by coercion to integer range 即使有8个向量,它也会杀死我的CPU和/或RAM(> expand.grid(v1,v8)). Here我发现了一些改进,建议使用外部或rep.int.这些解决方案适用于两个向量,因此我无法将其应用于12个向量,但我猜原理是相同的:它创建了驻留在内存中的大型矩阵.我想知道是否有类似python的xrange懒惰评估的东西? Here我发现了delayedAssign函数,但我想这无济于事,因为还有以下内容:
使用嵌套循环只解决这个问题吗? PS:我没有具体的问题,但是假设你需要使用接受12个整数参数的函数进行一些计算,出于某种原因.还假设您需要对这12个整数进行所有组合并将结果保存到文件中.使用12个嵌套循环并将结果连续保存到文件将起作用(尽管它会很慢但不会杀死你的RAM). Here显示了如何使用expand.grid和apply函数来替换两个嵌套循环.问题是使用expand.grid创建具有12个长度为8的向量的矩阵具有一些缺点: >生成这样的矩阵很慢 所以在我看来,功能方法比程序解决方案慢得多.我只是想知道是否有可能懒洋洋地创建大型数据结构,理论上它不适合内存并迭代它.就这样. 解决方法
一种(可以说是更“正确”)的方法是为@BenBolker建议的迭代器编写自己的迭代器(写入扩展的pdf是
here).缺乏更正式的东西,这里是一个穷人的迭代器,类似于expand.grid但是手动推进. (注意:考虑到每次迭代的计算比这个函数本身“更昂贵”,这就足够了.这可以真正改进,但“它有效”.)
每次返回返回的函数时,此函数都会返回一个命名列表(带有提供的因子).它是懒惰的,因为它没有扩展整个可能的列表;它本身并不是懒惰,它们应该立即“消耗”. lazyExpandGrid <- function(...) { dots <- list(...) sizes <- sapply(dots,length,USE.NAMES = FALSE) indices <- c(0,rep(1,length(dots)-1)) function() { indices[1] <<- indices[1] + 1 DONE <- FALSE while (any(rolls <- (indices > sizes))) { if (tail(rolls,n=1)) return(FALSE) indices[rolls] <<- 1 indices[ 1+which(rolls) ] <<- indices[ 1+which(rolls) ] + 1 } mapply(`[`,dots,indices,SIMPLIFY = FALSE) } } 样品用法: nxt <- lazyExpandGrid(a=1:3,b=15:16,c=21:22) nxt() # a b c # 1 1 15 21 nxt() # a b c # 1 2 15 21 nxt() # a b c # 1 3 15 21 nxt() # a b c # 1 1 16 21 ## <yawn> nxt() # a b c # 1 3 16 22 nxt() # [1] FALSE 注意:为了简洁显示,我使用as.data.frame(mapply(…))作为示例;它可以正常工作,但如果命名列表适合您,则无需转换为data.frame. 编辑 基于alexis_laz’s answer,这是一个大大改进的版本,它(a)更快,(b)允许任意搜索. lazyExpandGrid <- function(...) { dots <- list(...) argnames <- names(dots) if (is.null(argnames)) argnames <- paste0('Var',seq_along(dots)) sizes <- lengths(dots) indices <- cumprod(c(1L,sizes)) maxcount <- indices[ length(indices) ] i <- 0 function(index) { i <<- if (missing(index)) (i + 1L) else index if (length(i) > 1L) return(do.call(rbind.data.frame,lapply(i,sys.function(0)))) if (i > maxcount || i < 1L) return(FALSE) setNames(Map(`[[`,(i - 1L) %% indices[-1L] %/% indices[-length(indices)] + 1L ),argnames) } } 它不使用任何参数(自动递增内部计数器),一个参数(搜索和设置内部计数器)或向量参数(寻找每个参数并将计数器设置为最后一个,返回data.frame). 最后一个用例允许对设计空间的子集进行采样: set.seed(42) nxt <- lazyExpandGrid2(a=1:1e2,b=1:1e2,c=1:1e2,d=1:1e2,e=1:1e2,f=1:1e2) as.data.frame(nxt()) # a b c d e f # 1 1 1 1 1 1 1 nxt(sample(1e2^6,size=7)) # a b c d e f # 2 69 61 7 7 49 92 # 21 72 28 55 40 62 29 # 3 88 32 53 46 18 65 # 4 88 33 31 89 66 74 # 5 57 75 31 93 70 66 # 6 100 86 79 42 78 46 # 7 55 41 25 73 47 94 感谢alexis_laz对cumprod,Map和索引计算的改进! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |