根据其他变量的值选择一列相乘

Pick a column to multiply with, contingent on value of other variables

我仍在探索 R 的第一步,发现 SO 是一个很好的工具,可以帮助我了解更多信息并找到问题的答案。对于这个,我虽然没有在这里找到任何好的解决方案。

我有一个可以简化为这种结构的数据框:

set.seed(10)
df <- data.frame(v1 = rep(1:2, times=3), 
v2 = c("A","B","B","A","B","A"), 
v3 = sample(1:6), 
xA_1 = sample(1:6), 
xA_2 = sample(1:6),
xB_1 = sample(1:6), xB_2 = sample(1:6))

df 看起来像这样:

> df 
   v1 v2 v3   xA_1 xA_2 xB_1 xB_2
1  1  A  4    2    1    3    3
2  2  B  2    6    3    5    4
3  1  B  5    3    2    4    5
4  2  A  3    5    4    2    1
5  1  B  1    4    6    6    2
6  2  A  6    1    5    1    6

我现在想让 R 创建第四个变量,它依赖于 v1 和 v2 的值。我通过使用以下代码实现了这一点:

df <- data.table(df)
df[, v4 := ifelse(v1 == 1 & v2 == "A", v3*xA_1, 
        ifelse(v1 == 1 & v2 == "B", v3*xB_1,
         ifelse(v1 == 2 & v2 == "A", v3*xA_2,
          ifelse(v1 == 2 & v2 == "B", v3*xB_2, v3*1))))]

所以 v4 是通过将 v3 与包含 v1 和 v2 值的列相乘创建的 (例如,对于第 1 行:v1=1 and v2=A thus multiply v3=4 with xA_1=2 -> 8)。

> df$v4
[1]  8  8 20 12  6 30

显然,当 v1 和 v2 实际上具有比本例中更多不同的值时,我的 ifelse 方法很乏味。所以我正在寻找一种有效的方法来告诉 R if v1 == y & v2 == z, multiply v3 with column xy_z.

我尝试编写一个 for 循环,编写一个以 y 和 z 作为索引的函数并使用 apply 函数。然而,none 的效果如愿以偿。

我很感激任何想法!

你可以试试这个:

v4 <- c()
for(i in 1:nrow(df)){
  col <- paste("x",df$v2[i],"_",df$v1[i],sep="")
  v4 <- c(v4,df$v3[i]*df[i,col])
}

df$v4 <- v4

这是一个基本的 R 选项:

i <- paste0("x", df$v2, "_", df$v1)
df$v4 <- df$v3 * as.numeric(df[cbind(1:nrow(df), match(i, names(df)))])

对于下面提供的示例数据,它创建了一个列 v4 作为:

> df$v4
[1] 25 12  2  6  3 10

或者,如果您想要包含 "else" 条件以乘以 1,以防没有匹配的列名:

i <- paste0("x", df$v2, "_", df$v1)
tmp <- as.numeric(df[cbind(1:nrow(df), match(i, names(df)))])
df$v4 <- df$v3 * ifelse(is.na(tmp), 1, tmp)

示例数据:

df <- structure(list(v1 = c(1L, 2L, 1L, 2L, 1L, 2L), v2 = structure(c(1L, 
2L, 2L, 1L, 2L, 1L), .Label = c("A", "B"), class = "factor"), 
    v3 = c(5L, 4L, 1L, 6L, 3L, 2L), xA_1 = c(5L, 6L, 3L, 1L, 
    2L, 4L), xA_2 = c(6L, 4L, 2L, 1L, 3L, 5L), xB_1 = c(4L, 6L, 
    2L, 5L, 1L, 3L), xB_2 = c(5L, 3L, 2L, 4L, 1L, 6L)), .Names = c("v1", 
"v2", "v3", "xA_1", "xA_2", "xB_1", "xB_2"), row.names = c(NA, 
-6L), class = "data.frame")

这是一个标准的 "wide" table 问题 - 你想要的东西很难按原样做,但当数据是 "melted":

时很容易
dt = as.data.table(df)

melt(dt, id.vars = c('v1', 'v2', 'v3'))[variable == paste0('x', v2, '_', v1)
   ][dt, on = c('v1', 'v2', 'v3'), v3 * value]
#[1]  8  8 20 12  6 30