【问题标题】:How to vectorize a for loop in R如何矢量化 R 中的 for 循环
【发布时间】:2012-12-10 00:27:31
【问题描述】:

我正在尝试清理此代码,并想知道是否有人对如何在 R 中不循环运行它有任何建议。我有一个名为 data 的数据集,其中包含 100 个变量和 200,000 个观察值。我想要做的基本上是通过将每个观察值乘以特定标量来扩展数据集,然后将数据组合在一起。最后,我需要一个包含 800,000 个观察值(我要创建四个类别)和 101 个变量的数据集。这是我写的一个循环,它可以做到这一点,但它的效率非常低,我想要更快更高效的东西。

datanew <- c()
for (i in 1:51){
  for (k in 1:6){
    for (m in 1:4){

      sub <- subset(data,data$var1==i & data$var2==k)

      sub[,4:(ncol(sub)-1)] <- filingstat0711[i,k,m]*sub[,4:(ncol(sub)-1)]

      sub$newvar <- m

      datanew <- rbind(datanew,sub)

    }
  }
}

请让我知道您的想法并感谢您的帮助。

以下是一些具有 2K 观测值而不是 200K 的样本数据

# SAMPLE DATA
#------------------------------------------------#
  mydf <- as.data.frame(matrix(rnorm(100 * 20e2), ncol=20e2, nrow=100))
  var1 <- c(sapply(seq(41), function(x) sample(1:51)))[1:20e2]
  var2 <- c(sapply(seq(2 + 20e2/6), function(x) sample(1:6)))[1:20e2]
  #----------------------------------#
  mydf <- cbind(var1, var2, round(mydf[3:100]*2.5, 2))
  filingstat0711 <- array(round(rnorm(51*6*4)*1.5 + abs(rnorm(2)*10)), dim=c(51,6,4))
#------------------------------------------------#

【问题讨论】:

  • 请帮助我们帮助您,通过 (1) 发布一些示例数据,以及 (2) 用文字解释您希望在这里完成的工作。另请注意,您不需要引用您在 subset 中设置子集的 data.frame。

标签: r for-loop vectorization


【解决方案1】:

您可以尝试以下方法。请注意,我们将前两个 for 循环替换为对 mapply 的调用,将第三个 for 循环替换为对 lapply 的调用。 此外,我们正在创建两个向量,我们将组合它们以进行向量化乘法。

# create a table of the i-k index combinations using `expand.grid`
ixk <- expand.grid(i=1:51, k=1:6)

    # Take a look at what expand.grid does
    head(ixk, 60)


# create two vectors for multiplying against our dataframe subset
multpVec <- c(rep(c(0, 1), times=c(4, ncol(mydf)-4-1)), 0)
invVec   <- !multpVec

    # example of how we will use the vectors
    (multpVec * filingstat0711[1, 2, 1] + invVec)


# Instead of for loops, we can use mapply. 
newdf <- 
  mapply(function(i, k) 
    
    # The function that you are `mapply`ing is:
    # rbingd'ing a list of dataframes, which were subsetted by matching var1 & var2
    # and then multiplying by a value in filingstat
    do.call(rbind, 
        # iterating over m
        lapply(1:4, function(m)
          
          # the cbind is for adding the newvar=m, at the end of the subtable
          cbind(

            # we transpose twice: first the subset to multiply our vector. 
            # Then the result, to get back our orignal form
            t( t(subset(mydf, var1==i & mydf$var2==k)) * 
              (multpVec * filingstat0711[i,k,m] + invVec)), 
          
          # this is an argument to cbind
          "newvar"=m) 
    )), 

    # the two lists you are passing as arguments are the columns of the expanded grid
    ixk$i, ixk$k, SIMPLIFY=FALSE
  )

# flatten the data frame
newdf <- do.call(rbind, newdf)


需要注意的两点:
  1. 尽量不要使用datatabledfsub等常用函数 在上面的代码中,我使用mydf 代替了data

  2. 您可以使用 apply(ixk, 1, fu..) 代替我使用的 mapply,但我认为在这种情况下,mapply 会使代码更简洁

【讨论】:

    猜你喜欢
    • 2020-05-03
    • 1970-01-01
    • 2019-02-28
    • 2018-12-08
    • 2014-10-03
    • 1970-01-01
    • 2016-02-11
    • 1970-01-01
    相关资源
    最近更新 更多