在循环中创建子集或在R中应用函数的更快的方法

时间:2016-11-02 14:41:36

标签: r

我是R的新手,所以请提前为我的代码中的错误表单道歉。

我正在尝试找出逐行浏览数据框的最佳方法,并根据引用该行中其他列的逻辑或完全不同的数据框修改值。问题是我正在使用的逻辑需要为每一行创建和子集化数据帧以检索最小值。我的实际数据集是47000行和15列,因此创建47,000个子集需要很长时间。

以下是帮助描述我所说的内容的示例数据集。

df1 <- data.frame('A' = c(rep("Beer", 2), rep("Chip", 2)), 'B' = c(NA, 3,
       NA,9), 'C' = 5:8, 'D' = NA)
df2 <- data.frame('Q' = c(rep("Beer", 2), rep("Chip", 2)), 'R' = 6:9, 'S' = 
       c(12, 15, 4, 18), 'T' = c(23, 45, 75, 34)) 

DF1:

  A    B    C    D
 Beer  NA   5    NA
 Beer  3    6    NA
 Chip  NA   7    NA
 Chip  9    8    NA

DF2:

  Q    R    S    T
 Beer  6    12    23
 Beer  7    15    45
 Chip  8    4     75
 Chip  9    18    34

这个循环做了我想要的,即检查列B中的值是否为NA,如果不是则在列D中使用该值,如果它是NA则从过滤的子集中检索最小值df2。在实际使用案例中,我有其他过滤条件。

require(dplyr)

for (i in 1:nrow(df1)) {
  if (!(is.na(df1$B[i]))) {
    df1$D[i] <- df1$B[i]}
  else {x <- filter(df2,  df1$A[i] == df2$Q)
      x <- min(x$S)
      df1$D[i] <- x
  }
}

每个人都说要避免R中的循环,所以我使用apply创建了这个函数,这也有效(虽然有点难以理解):

FUNC <- function(x) {
  apply(x, 1, function(y) {
    if (!(is.na(y[2]))) {
      y[4] <- y[2]}
    else {z <- filter(df2,  y[1] == df2$Q)
    z <- min(z$S)
    y[4] <- z}
  }
  )
}

df1$D <- as.numeric(FUNC(df1))

输出:

     A    B    C    D
    Beer  NA   5    12
    Beer  3    6    3
    Chip  NA   7    4
    Chip  9    8    9

旁白问题:有没有办法按名称而不是按索引位置引用向量y中的项目?

那么有更好的方法吗?现在这两种方法需要大约5-8分钟来运行47,000多行,这对我来说似乎很长。

1 个答案:

答案 0 :(得分:0)

df1$D <- df2 %>% 
  rename(A=Q) %>% 
  group_by(A) %>% 
  summarise(D=min(S)) %>% 
  right_join(df1, by="A") %>% 
  mutate(D=ifelse(is.na(B), D.x, B)) %>% 
  `[[`("D")