[英]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
。 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.