R:对排序子集的所有行应用函数,如果满足条件则完成计算

R: apply a function to all rows that orders a subset and completes a calculation if a condition is met

我想对每一行应用一个函数,之后 根据 if/else 语句对该行的子集进行排序。然后用结果填充数据框中的新列。我有超过 200 万行,因此执行此操作的 for 循环效率非常低。

给定以下数据框:(为 r2evans 编辑)

df<-as.data.frame(cbind(matrix(LETTERS[1:3], ncol=1),matrix(sample.int(100,size=15),nrow=3,ncol=5))

> df
  V1 V2 V3 V4 V5 V6
1  A 77 79 32  5  4
2  B 57 24 68 65 45
3  C 66 60 82 74 22

有没有办法在没有 for 循环的情况下将以下循环应用于每一行,因为我实际上有超过 2630800 行?

df$num <- 0
df[2:7] <- sapply(df[2:7],as.numeric)
names(df) <- c("first_name", "sec", "A", "B", "C", "D", "num")

下面的 if 语句需要列的名称: (也编辑为只排序一次)

for (i in seq_len(nrow(df))) {
     row = sort(df[i,3:6])
     if (df[i,1]==names(row)[4]) {
         df$num[i] = row[3]/(row[3]+row[4])
     } else {
         df$num[i] = row[4]/(row[3]+row[4])
     }
 }

这样我得到了这个结果:

> df
  first_name sec  A  B  C  D       num
1          A  77 79 32  5  4 0.2882883
2          B  57 24 68 65 45 0.4887218
3          C  66 60 82 74 22  0.525641

我不确定如何使用 apply 执行此操作,是否在想这样的事情?尽管这不起作用,而且我不确定如何合并 if/else 条件:

df$num <- apply(df, 1, function(x) unlist(x[3:6][order(x[3:6])][3]/(x[3:6][order(x[3:6])][3]+x[3:6][order(x[3:6])][4])))

这里有一些硬编码(列索引)的小蛮力方法。

cols <- 3:6
sorted2 <- t(apply(df[,cols], 1, sort, decreasing = TRUE))[,1:2]
sorted2
#   [,1] [,2]
# 1   79   32
# 2   68   65
# 3   82   74
df$num <- ifelse(df[,1] == names(df)[cols][max.col(df[,cols])],
                 sorted2[,2], sorted2[,1]) /
            rowSums(sorted2)
df
#   first_name sec  A  B  C  D       num
# 1          A  77 79 32  5  4 0.2882883
# 2          B  57 24 68 65 45 0.4887218
# 3          C  66 60 82 74 22 0.5256410

备注:

  • 我定义cols这样如果你改变列,你只需要改变一次。
  • 您的代码倾向于比较 first_name 是否与列名匹配,并据此确定您是使用 cols 列中的“最大值”还是“第二最大值”,以及然后将 that 数字除以两个最大数字的总和。为此,我计算 sorted2,它始终在第 1 列中具有最大值,在第 2 列中具有第二个最大值,从而使 rowSums 和 max/2nd-max 访问 immediate/easy.
  • 我本可以使用 df$first_name 而不是 df[,1],你的选择。

这应该比 for 循环或 sapply 工作得更好,因为它是完全矢量化的。