繁体   English   中英

根据多列条件创建新列

[英]Create a new column based on a condition on multiple columns

我有以下数据集:

library(data.table)
set.seed(123)
dt <- data.table(x_1 = c(3,2,2,1,3,2,1,2,3,3),
                 x_2 = c(2,1,1,3,2,3,3,1,2,3),
                 x_3 = c(2,3,3,2,1,2,3,3,1,1),
                 y_1 = sample(2, 10, replace = T),
                 y_2 = sample(2, 10, replace = T),
                 y_3 = sample(2, 10, replace = T))

我想在x列上执行if else操作,如果任何x列等于1,它将创建一个具有相应y列值的新列。 例如,在第5行中, x_3 = 1 ,因此新列应返回对应于y_3的值。

我的想法是返回与条件匹配的x列的名称作为中间列,然后使用值后缀(1,2,3)从相应的y列中提取值。

但是创建中间列的第一步是创建一个列表,不匹配条件的行返回character(0)

cols <- c("x_1", "x_2", "x_3")
dt$int <- apply(dt[,..cols], 1, function(x) names(which(x == 1)))

我想要的输出:

x_1 x_2 x_3 y_1 y_2 y_3 new
3   2   2   1   2   2   NA
2   1   3   2   1   2   1
2   1   3   1   2   2   2
1   3   2   2   2   2   2
3   2   1   2   1   2   2
2   3   2   1   2   2   NA
1   3   3   2   1   2   2
2   1   3   2   1   2   1
3   2   1   2   1   1   1
3   3   1   1   2   1   1

关于如何实现这一点的任何想法? 基于数据表的解决方案将是更可取的。

不确定如何处理同一行中x_ *中没有任何1或多个的情况。

这是一种可能的方法,使用data.table::melt成长格式,然后在x_中找到第一个位置1 ,然后访问y_

dt[, rn:=.I]
dt[melt(dt, id.vars="rn", meas=list(c("x_1", "x_2", "x_3"), c("y_1", "y_2", "y_3")))[,
    value2[which(value1==1L)[1L]], by=.(rn)], yval := V1, on=.(rn)]

输出:

    x_1 x_2 x_3 y_1 y_2 y_3 rn yval
 1:   3   2   2   1   2   2  1   NA
 2:   2   1   3   2   1   2  2    1
 3:   2   1   3   1   2   2  3    2
 4:   1   3   2   2   2   2  4    2
 5:   3   2   1   2   1   2  5    2
 6:   2   3   2   1   2   2  6   NA
 7:   1   3   3   2   1   2  7    2
 8:   2   1   3   2   1   2  8    1
 9:   3   2   1   2   1   1  9    1
10:   3   3   1   1   2   1 10    1

编辑:合并thelatemail的简洁版本,也可以处理多个版本

dt[, yval := 
    melt(dt, id.vars="rn", measure.vars=patterns("^x_", "^y_"))[value1==1L][
        dt, value2, on=.(rn), mult="first"]
]

另一种可能的方案

ix <- dt[, max.col(.SD == 1) * NA^(!rowSums(.SD == 1)), .SDcols = 1:3]

dt[, newcol := as.matrix(.SD)[cbind(.I, ix)]
   , .SDcols = 4:6][]

这使:

  x_1 x_2 x_3 y_1 y_2 y_3 newcol 1: 3 2 2 1 2 2 NA 2: 2 1 3 2 1 2 1 3: 2 1 3 1 2 2 2 4: 1 3 2 2 2 2 2 5: 3 2 1 2 1 2 2 6: 2 3 2 1 2 2 NA 7: 1 3 3 2 1 2 2 8: 2 1 3 2 1 2 1 9: 3 2 1 2 1 1 1 10: 3 3 1 1 2 1 1 

笔记:

  • 您也可以使用as.data.frame代替as.matrix
  • 如果你有一个以上的X列等于1,则需要使用ties.method的-parameter max.col 您可以选择"random""first""last"

如果您事先不知道列位置,可以将上述解决方案概括为:

xcols <- like(names(dt), "x")
ycols <- like(names(dt), "y")

ix <- dt[, max.col(.SD == 1) * NA^(!rowSums(.SD == 1)), .SDcols = xcols]

dt[, newcol := as.matrix(.SD)[cbind(.I, ix)]
   , .SDcols = ycols][]

这是Map一个选项。 子集“x”和“y”列的data.table( .SD )子集,创建“x”列的逻辑向量,并获取“x”为1的相应“y”值,然后将其折叠使用pmin到单个元素(假设'x列每行不超过1)

dt[, new := do.call(pmin, c(Map(function(x, y) y * NA^(x != 1),
      .SD[, 1:3, with = FALSE], .SD[, 4:6, with = FALSE]), na.rm = TRUE)), ]
dt
#    x_1 x_2 x_3 y_1 y_2 y_3 new
# 1:   3   2   2   1   2   2  NA
# 2:   2   1   3   2   1   2   1
# 3:   2   1   3   1   2   2   2
# 4:   1   3   2   2   2   2   2
# 5:   3   2   1   2   1   2   2
# 6:   2   3   2   1   2   2  NA
# 7:   1   3   3   2   1   2   2
# 8:   2   1   3   2   1   2   1
# 9:   3   2   1   2   1   1   1
#10:   3   3   1   1   2   1   1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM