我下面有这个数据集:
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列值的新列。例如在第五行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
关于如何实现这一目标的任何想法?基于数据表的解决方案将是更可取的。
答案 0 :(得分:2)
不确定在同一行的x_ *中如何处理没有任何1或多个1的情况。
这是一种可能的方法,将sparsehash/internal/libc_allocator_with_realloc.h:68:40: warning:
‘void* realloc(void*, size_t)’ moving an object of non-trivially copyable type
‘struct std::pair<const std::__cxx11::basic_string<char>, int>’;
use ‘new’ and ‘delete’ instead [-Wclass-memaccess]
return static_cast<pointer>(realloc(p, n * sizeof(value_type)));
~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
转换为长格式,然后在x_ 中找到第一个位置1,然后访问y _ 值
data.table::melt
输出:
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)]
编辑:合并了latemail的简洁版本,并且还可以处理多个版本
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
答案 1 :(得分:2)
另一种可能的解决方案:
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.matrix
代替as.data.frame
。ties.method
的{{1}}参数。您可以在max.col
,"random"
或"first"
之间进行选择。如果您事先不知道列的位置,则可以将以上解决方案归纳为:
"last"
答案 2 :(得分:0)
这是Map
的一个选项。为“ x”和“ y”列子集data.table(.SD
)的子集,创建“ x”列的逻辑向量,并获得相应的“ y”值,其中“ x”为1,并使用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