根据条件从辅助数据表采样到主数据表

Sampling from a secondary datatable to the main datatable based on a condition

我有两个数据表 dt_maindt_unit

set.seed(1)
dt_main<-data.table(ID=sample(1:20,size=10),Group=sample(1:3,size=10,replace=TRUE),Unit=0)
dt_unit<-data.table(Group=sample(1:3,size=10,replace=TRUE),Unit_id=sample(1000:3000,size=10,replace=TRUE))

dt_main 看起来像这样:

> dt_main
    ID Group Unit
 1:  4     1    0
 2:  7     1    0
 3:  1     1    0
 4:  2     2    0
 5: 13     2    0
 6: 19     2    0
 7: 11     2    0
 8: 17     3    0
 9: 14     1    0
10:  3     3    0

dt_unit 看起来像这样:

> dt_unit
    Group Unit_id
 1:     1    2624
 2:     1    2963
 3:     1    1974
 4:     1    1800
 5:     2    1851
 6:     1    1930
 7:     1    1325
 8:     2    1329
 9:     2    1553
10:     2    2445

我想用相同的 [=24] 从 dt_unitdt_main 抽取一个 Unit_id 来填充 dt_main 中的 Unit 列=].

例如,对于 dt_main 中的第一行(因此 Group=1),代码应查找 dt_unit 并找到 Group 为 1 的行(见下文)和 select 一个 Unit_id 并将其插入 Unit.

> dt_unit[Group==1]
   Group Unit_id
1:     1    2624
2:     1    2963
3:     1    1974
4:     1    1800
5:     1    1930
6:     1    1325

我试过这样的方法,它为每一行分配了相同的数字:

dt_main[,Unit:=sample(dt_unit[Group==Group]$Unit_id,size=1)]

我也试过sapply但没用。

这是一个基本的 R 解决方案,我们每次都匹配组和样本 1 值,

dt_main$Unit <- sapply(dt_main$Group, function(i) {
                                  v1 <- dt_unit$Unit_id[dt_unit$Group %in% i]; 
                                  if (length(v1) > 0) {sample(v1, 1) } else {NA}
                                  })


#    ID Group Unit
# 1:  4     1 1930
# 2:  7     1 1325
# 3:  1     1 1325
# 4:  2     2 1329
# 5: 13     2 2445
# 6: 19     2 2445
# 7: 11     2 1851
# 8: 17     3   NA
# 9: 14     1 1930
#10:  3     3   NA

您可以通过 Group 和 select 加入 dt_maindt_unit 每个 ID 的随机行。

使用 dplyr,您可以通过以下方式完成此操作:

library(dplyr)
left_join(dt_main, dt_unit, by = 'Group') %>% group_by(ID) %>% sample_n(1)


#     ID Group Unit_id
#   <int> <int>   <int>
# 1     1     1    1800
# 2     2     2    2445
# 3     3     3      NA
# 4     4     1    2963
# 5     7     1    1800
# 6    11     2    1851
# 7    13     2    1553
# 8    14     1    1325
# 9    17     3      NA
#10    19     2    2445

我从 data.table 创建中删除了 Unit 列。

另一个答案mapply,我用它来处理有多个条件的情况。在这种情况下,在查找时我会检查 Group 列是否匹配并且 dt_main 中的新列 (Size) 是否大于 dt_unit 中的新列。作为 OP,我必须向原始 post 添加另一个条件,因此添加此解决方案以帮助未来的用户。

my_fun<-function(var1,var2)
{
  d<-dt_unit[(Group%in%var1)&(Size>=var2)]
  if(nrow(d)>=2){
  sample(x=d$Unit_id,size=1,replace=T)
  }else
  {d$Unit_id}
}
vars1<-dt_main$Group
vars2<-dt_main$Size
dt_main$Unit<-mapply(my_fun,vars1,vars2)