这是我正在使用的示例表:

n = c(rep("A",3),rep("B",3),rep("C",3))
m = c("X", "Y", "Z", "X", "Y", "Z", "X", "Y", "Z")
s = 1:9
b = 5:13
c = 20:28
d = c(rep("abc", 9))
df = data.frame(d, n, m, s, b, c)
df

该表如下所示:
d   n   m   s   b   c
abc A   X   1   5   20
abc A   Y   2   6   21
abc A   Z   3   7   22
abc B   X   4   8   23
abc B   Y   5   9   24
abc B   Z   6   10  25
abc C   X   7   11  26
abc C   Y   8   12  27
abc C   Z   9   13  28

我将每一行称为它的列n和m值的串联(例如AX行,CZ行等)。我想将A行的每一行除以AY行,将B行的每一行除以BY行,每个C行乘以CY行(可能并不总是Y,有时是X或Z)。我本质上是想以X(Y,Y或Z(列m))为基础,按组(其中n列为组)对数据(s,b和c列)进行基础计算。

我需要d,n和m列以保持不变。如果可能的话,我想通过直接引用代码中的X,Y或Z来表示哪一行将作为基数,而不是通过[1],[2]或[3]来实现(因为它们可能不一定总是相同的顺序,并且对用户而言更直观)。我是R的新手,并且使用dplyr,但是我还没有办法找到一种好的方法。

谢谢你的帮助。

最佳答案

使用data.table

library(data.table)

setDT(df)

divselect <- "Y"

set(df, j = "s", value = as.numeric(df[["s"]]))
set(df, j = "b", value = as.numeric(df[["b"]]))
set(df, j = "c", value = as.numeric(df[["c"]]))
set命令是为了避免错误。当前的列是integer,但是您将使它们成为double。如果在您的实际示例中,它们已经是double,则无需这样做。
divselect的值更改您用作基础的列行。您可以根据需要将其更改为XZ
df[, `:=`(s = s/s[m == divselect],
          b = b/b[m == divselect],
          c = c/c[m == divselect]),
   by = n]

结果:
#      d n m     s         b         c
# 1: abc A X 0.500 0.8333333 0.9523810
# 2: abc A Y 1.000 1.0000000 1.0000000
# 3: abc A Z 1.500 1.1666667 1.0476190
# 4: abc B X 0.800 0.8888889 0.9583333
# 5: abc B Y 1.000 1.0000000 1.0000000
# 6: abc B Z 1.200 1.1111111 1.0416667
# 7: abc C X 0.875 0.9166667 0.9629630
# 8: abc C Y 1.000 1.0000000 1.0000000
# 9: abc C Z 1.125 1.0833333 1.0370370

跟进



是的,您可以通过在lapply的内部或外部使用data.table来执行此操作。
setDT(df)

divselect <- "Y"

funcnumeric <- function(x) {
  set(df, j = x, value = as.numeric(df[[x]]))
  NULL
}

modcols <- names(df)[!(names(df) %in% c("d", "n", "m"))]

a <- lapply(modcols, funcnumeric)

这将替换第一个答案中的三个set命令。而不是指定每个,我们使用lapply在不是dnm的每一列上执行功能。注意,我返回NULL以避免杂乱的函数返回文本;由于这是data.table,因此已全部完成。
funcdiv <- function(x, pos) {
  x/x[pos]
}

df[ , (modcols) := lapply(.SD,
                          funcdiv,
                          pos = which(m == divselect)),
    by = n,
    .SDcols = modcols]

这样做与以前略有不同。在这里,我们创建了一个简单的函数,该函数将矢量除以该矢量的值,即pos参数指定的位置。我们将其应用于.SD中的每一列,并将pos值传递为m列等于divselect值的位置,在这种情况下,它等于Y。由于我们指定了by = n,因此将为pos中的每个值确定funcdiv的vector和n参数。参数.SDcols指定我们要对该功能进行lapply,这与我们分配给变量modcols的一组列相同。我们将所有这些都分配回位到modcols

结果:
#      d n m     s         b         c
# 1: abc A X 0.500 0.8333333 0.9523810
# 2: abc A Y 1.000 1.0000000 1.0000000
# 3: abc A Z 1.500 1.1666667 1.0476190
# 4: abc B X 0.800 0.8888889 0.9583333
# 5: abc B Y 1.000 1.0000000 1.0000000
# 6: abc B Z 1.200 1.1111111 1.0416667
# 7: abc C X 0.875 0.9166667 0.9629630
# 8: abc C Y 1.000 1.0000000 1.0000000
# 9: abc C Z 1.125 1.0833333 1.0370370

关于r - 按组将所有行除以引用行,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45224162/

10-13 08:17