应用函数遍历数据框并基于索引列生成列

问题描述 投票:0回答:1

所以让我描述一下数据:

  • abcxyz是指标。
  • hit基本上是索引号,例如:
    • 命中值3表示abc3和xyz3中的对应值
    • hit 4表示abc4,xyz4

数据

dat <- data.frame( abc1=c(7, 0, 7), 
                   abc2=c(5, 10, 20), 
                   abc3=c(0, 0, 10), 
                   abc4=c(3, 5, 19), 
                   abc5=c(2, 2, 0), 
                   abc6=c(2, 26, 0),
                   xyz1=c(0, 2, 0),
                   xyz2=c(1, 1, 6),
                   xyz3=c(8, 2, 0),
                   xyz4=c(6, 3, 5),
                   xyz5=c(9, 2, 2),
                   xyz6=c(4, 0, 0),
                   hit=c(3, 4, 4))

我需要做的是在命中前后找到abc和xyz。下面的for循环非常适合小型数据集,但是如果数据超过10万行,则循环似乎永远运行。

for (c in c('abc','xyz')){
  for (i in 1:nrow(dat)){
    for (m in -2:2){

      dat[[paste(c,'hit', m)]][i] = dat[i,paste(c, dat$hit[i]-m, sep = "")]
    }
  }
}

在输出文件中,第1行的'abc hit 0'表示:hit = 3,它依次从abc3中选择值并分配给abc hit 0

abc hit -1转换为hit = 3-1 = 2,它指向abc2xyz2

我知道3个for循环是个坏主意。请通过使用Apply函数或任何其他减少执行时间的方法来帮助我更好地编写代码。

r dataframe for-loop optimization apply
1个回答
0
投票

您似乎在for循环中反转了'm':它从-2到2,但是然后您得到dat$hit - m-您想要的是减法吗?还是dat$hit + m

您可以执行以下操作-我尚未在大型数据集上对其进行过测试,但可以尝试一下:

dat1 <- do.call(rbind, 
                lapply(split(dat, 1:NROW(dat)), 
                       function(x) {
                          z <- x[paste0('abc', x$hit + 2:-2)]; 
                          names(z) <- paste0('abc', -2:2); 
                          z 
                       }
                ))

split函数为您提供数据框的行,愉快地保留列名,然后您可以在其上使用lapply函数逐行操作。

您可以通过在hit上加上-2到2来查找每一行的相关列。

然后您将生成的列表重新粘贴到一个数据框中。

更新:实际上,即使对于3万行,上述操作也相当慢。这样更快:

dat1 <- t(sapply(split(dat, 1:NROW(dat)), 
                       function(x) unname(x[paste0('abc', x$hit + 2:-2)])  
                ))
dat1 <- as.data.frame(dat1)
colnames(dat1) <- paste0('abc', -2:2)
© www.soinside.com 2019 - 2024. All rights reserved.