加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

对于R OR,Python的xrange替代方法如何循环遍历大型数据集?

发布时间:2020-12-20 10:34:07 所属栏目:Python 来源:网络整理
导读:以下示例基于 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:
以下示例基于 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函数,但我想这无济于事,因为还有以下内容:

Unfortunately,R evaluates lazy variables when they are pointed to by
a data structure,even if their value is not needed at the time. This
means that infinite data structures,one common application of
laziness in Haskell,are not possible in R.

使用嵌套循环只解决这个问题吗?

PS:我没有具体的问题,但是假设你需要使用接受12个整数参数的函数进行一些计算,出于某种原因.还假设您需要对这12个整数进行所有组合并将结果保存到文件中.使用12个嵌套循环并将结果连续保存到文件将起作用(尽管它会很慢但不会杀死你的RAM). Here显示了如何使用expand.grid和apply函数来替换两个嵌套循环.问题是使用expand.grid创建具有12个长度为8的向量的矩阵具有一些缺点:

>生成这样的矩阵很慢
>如此大的矩阵消耗大量内存(687亿行和8列)
>使用apply进一步迭代此矩阵也很慢

所以在我看来,功能方法比程序解决方案慢得多.我只是想知道是否有可能懒洋洋地创建大型数据结构,理论上它不适合内存并迭代它.就这样.

解决方法

一种(可以说是更“正确”)的方法是为@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和索引计算的改进!

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读