【问题标题】:For each row in a data.table, get random index for matching rows in another data.table对于 data.table 中的每一行,获取另一个 data.table 中匹配行的随机索引
【发布时间】:2022-01-11 16:50:29
【问题描述】:

我有一个包含几列因素的 data.table (dt1),例如

ID    Factor1    Factor2    Factor3
01          A          X          J
02          B          X          L
03          C          Y          J

每一行都有一个唯一的 ID,但可能有多行具有相同的因子变量组合。我有另一个表(dt2),它具有完全相同的因子变量,但要大得多,并且没有 ID 列。 dt1 中的每个因子组合都会在 dt2 中出现多次。例如

Factor1    Factor2    Factor3
      A          Z          K
      A          X          J
      A          X          J
      B          J          L
      B          X          L
      C          X          J
      C          Y          J

我想为 dt1 中的每一行返回 dt2 中具有相同因子变量组合的随机行的索引。

我想我可以使用.I[sample(.N,1)] 返回一个随机索引,但不知道如何按每行的相关因素进行分组。我是否需要创建一个函数来依次获取 dt1 中的每一行,或者是否有一种矢量化的方式来实现这一点?

所需的输出可以是长度为nrow(dt1) 的向量,也可以是 dt1 中的附加列。它将包含来自 dt2 的行索引。例如像这样(ID 01 的索引可能是 2 或 3):

ID    Factor1    Factor2    Factor3    Index
01          A          X          J        3
02          B          X          L        5
03          C          Y          J        7

非常感谢任何帮助。

【问题讨论】:

  • 请提供dt2的样本数据和想要的输出。
  • @Wimpel 添加了这些

标签: r data.table match


【解决方案1】:
# create index in dt2
dt2[, index := .I]
# set unique key dt1
setkey(dt1, ID)
# get factor columns
cols <- grep("Factor", names(dt1), value = TRUE)
#build code to eval/parse in a string
run.text <- paste0("dt1[dt1, index := sample(dt2[", 
                   paste0(cols, " == i.", cols, collapse = " & "), 
                   ", ]$index, 1), by = .EACHI]")
#eval/parse the string
eval(parse(text = run.text))
#    ID Factor1 Factor2 Factor3 index
# 1:  1       A       X       J     2
# 2:  2       B       X       L     5
# 3:  3       C       Y       J     1
# 4:  4       A       X       J     3

使用的样本数据(在 dt1 中有重复)

library(data.table)
dt1 <- fread("ID    Factor1    Factor2    Factor3
01          A          X          J
02          B          X          L
03          C          Y          J
04          A          X          J")

dt2 <- fread("Factor1    Factor2    Factor3
      A          Z          K
      A          X          J
      A          X          J
      B          J          L
      B          X          L
      C          X          J
      C          Y          J")

【讨论】:

  • 谢谢 - 这看起来不错。在我的实际用例中,dt1 和 dt2 中有很多 Factor 列 - 有没有办法像这样匹配它们而无需手动将它们全部写出来?
  • 已编辑答案.. 我能想到的第一件事是一个 eval/parse 解决方案,您在运行之前将整行粘贴在一起.. 似乎可以解决问题。
【解决方案2】:

UPD
我想你想做这样的事情:

dt2[, Index := as.character(.I)]
cols = c("Factor1", "Factor2", "Factor3")
dt = dt2[, lapply(.SD, list), keyby = cols]
dt = merge(dt1, dt, by = cols, all.x = T)
dt[, .(Index = sample(Index[[1]], 1)), keyby = c("ID", cols)]

【讨论】:

  • 谢谢。如问题中所述, dt1 中的多行可以具有相同的因子变量组合。使用这种方法,它们都将匹配相同的索引 - 我希望每行的选择都是随机的。即如果 dt1 中有两行与 ID 01 具有相同的特征,那么我希望每行都能够匹配索引 2 或 3。
  • 是的,你是对的。我更新代码。
【解决方案3】:
library(data.table)

# set up the data
set.seed(94)
dt1 <- setnames(as.data.table(matrix(sample(3, 9, TRUE), 3)), paste0("Factor", 1:3))
dt2 <- dt1[sample(3, 10, TRUE)]
dt1
#>    Factor1 Factor2 Factor3
#> 1:       2       1       2
#> 2:       2       3       3
#> 3:       2       3       2
dt2
#>     Factor1 Factor2 Factor3
#>  1:       2       3       2
#>  2:       2       3       3
#>  3:       2       3       2
#>  4:       2       3       2
#>  5:       2       3       2
#>  6:       2       1       2
#>  7:       2       3       2
#>  8:       2       3       2
#>  9:       2       3       2
#> 10:       2       3       3

# create helper columns and do a rolling join
dt2[, R := seq_len(.N)/.N, by = names(dt2)][, Index := .I]
print(dt2[dt1[, R := runif(.N)], on = names(dt1), roll = -Inf][, R := NULL])
#>    Factor1 Factor2 Factor3 Index
#> 1:       2       1       2     6
#> 2:       2       3       3     2
#> 3:       2       3       2     3

【讨论】:

    【解决方案4】:

    你也可以试试

    1. 添加索引
    2. 合并dt1dt2 然后使用sample(.N,1) 采样
    cols = names(dt2)
    dt2[,index := .I]
    dt2[dt1, on = (cols)][,.SD[sample(.N,1)],.(ID)]
    

    或一排答案

    dt2[,index := .I][dt1, on = (cols)][,.SD[sample(.N,1)],.(ID)]
    

    更新

    library(data.table)
    dt1 <- fread("ID    Factor1    Factor2    Factor3
    01          A          X          J
    02          B          X          L
    03          C          Y          J")
    dt2 <- fread("Factor1    Factor2    Factor3
          A          Z          K
          A          X          J
          A          X          J
          B          J          L
          B          X          L
          C          X          J
          C          Y          J")
    cols <- names(dt2)[1:3]
    dt2[,index := .I][dt1, on = (cols)][,.SD[sample(.N,1)],.(ID)]
    #>       ID Factor1 Factor2 Factor3 index
    #>    <int>  <char>  <char>  <char> <int>
    #> 1:     1       A       X       J     3
    #> 2:     2       B       X       L     5
    #> 3:     3       C       Y       J     7
    

    reprex package 创建于 2021-12-07 (v2.0.1)

    【讨论】:

    • 我无法让它工作,我认为是因为添加索引列也会修改 cols 对象。
    • 你确定吗?我已经对其进行了测试,您可以看到更新的答案。也许你忘记初始化dt1dt2
    • 添加索引列如果在添加索引列后检查cols的值,请不要修改cols对象。
    猜你喜欢
    • 2017-10-19
    • 1970-01-01
    • 1970-01-01
    • 2013-04-23
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2018-09-15
    • 1970-01-01
    相关资源
    最近更新 更多