【问题标题】:Conditional merging on multiple columns多列条件合并
【发布时间】:2020-03-10 11:48:16
【问题描述】:

我有两个 data.tables。我想将第二个 data.table 中的信息与第一个合并:

DT1 <- fread(
"Val C   D  E   F   iso   year   
1    NA  1  NA  NA  NLD   2001
1    NA  2  NA  NA  NLD   2002       
1    NA  3  NA  NA  GRC   2001             
1    NA  3  NA  NA  GRC   2002",
header = TRUE)

DT2 <- fread(
"Val name  O   P  Q   R   iso   year   
1   A     NA  1  NA  NA  NLD   2001
1   A     NA  2  NA  NA  NLD   2001   
1   B     NA  1  NA  NA  NLD   2001
1   B     NA  2  NA  NA  NLD   2002
1   A     NA  1  NA  NA  NLD   2002
1   B     NA  2  NA  NA  NLD   2002         
1   C     NA  3  NA  NA  GRC   2001  
1   C     NA  3  NA  NA  GRC   2001
1   C     NA  3  NA  NA  GRC   2001        
1   A     NA  3  NA  NA  GRC   2002
1   A     NA  3  NA  NA  GRC   2002          
1   B     NA  3  NA  NA  GRC   2002",
header = TRUE)

我想将DT2name下的信息添加到DT1如下。如果 iso == NLD 名称 A 存在(无论多久),则 A 列将用 A 填充,如果不存在则保持 NA:

DT1 <- fread(
"Val    C   D  E   F   iso   year   A B C
 1      NA  1  NA  NA  NLD   2001   A B NA
 1      NA  2  NA  NA  NLD   2002   A B NA   
 1      NA  3  NA  NA  GRC   2001   NA NA C         
 1      NA  3  NA  NA  GRC   2002   A B NA",
header = TRUE)

但我不知道怎么去那里。我一直在尝试类似的东西:

DT[,A:="A"]
DT[,B:="B"]
DT[,C:="C"]
DT2$name[DT, on=c(iso="iso", year="year", name="A"), nomatch=0L]

merge(DT, DT2$name, on=c(iso="iso", year="year", A="name"), all.x = TRUE, allow.cartesian=FALSE)

但我认为必须以不同的方式解决它。谁能帮帮我?

【问题讨论】:

  • 所以“O P Q R”列不相关?
  • 我不确定这是否是您想要的输出,但可能是:DT3 &lt;- merge(DT1, DT2, by=c('Val', 'iso', 'year'), all=T),然后是DT3[iso=='NLD' &amp; name == 'A', A := 'A']
  • @zx8754 确实如此。我主要是让这个例子稍微复杂了一点,因为否则我有时会得到不够通用的解决方案,无法应用于实际数据。只有name 列是相关的。

标签: r merge data.table reshape melt


【解决方案1】:

另一种使用键合并的方法:

library(data.table)
#adding a key column "temp" to both DT1 and DT2
DT1[,temp:=paste0(iso,year,"_",D)]
DT2[,temp:=paste0(iso,year,"_",P)]
#merge accoring to "temp"
DT3 <- merge(DT1,DT2)
#Casting variable name, a warning pops-out saying it uses lenght as aggregation
DT3 <- dcast(merge(DT1,DT2),Val+C+D+E+F+iso+year~name)

#output
DT3
   Val  C D  E  F iso year A B C
1:   1 NA 1 NA NA NLD 2001 1 1 0
2:   1 NA 2 NA NA NLD 2002 0 2 0
3:   1 NA 3 NA NA GRC 2001 0 0 3
4:   1 NA 3 NA NA GRC 2002 2 1 0

最后使用this 答案转换为所需的形式,我将其转换回数据框以更改最后三列 A、B、C 的值。请注意,C 是重复的,所以我称它们为作为索引。

DT_final <- as.data.frame(DT3)
ind <- which(DT_final[,8:10]>0,arr.ind=TRUE) # is there a positive value?
DT_final[,8:10][ind]<- names(DT_final[,8:10])[ind[,"col"]]# if so change to the column name.
ind <- which(DT_final[,8:10]==0 ,arr.ind=TRUE)# is there zero  value?
DT_final[,8:10][ind]<- NA # if so change to NA

DT_final
  Val  C D  E  F iso year    A    B    C
1   1 NA 1 NA NA NLD 2001    A    B <NA>
2   1 NA 2 NA NA NLD 2002 <NA>    B <NA>
3   1 NA 3 NA NA GRC 2001 <NA> <NA>    C
4   1 NA 3 NA NA GRC 2002    A    B <NA>

【讨论】:

    【解决方案2】:

    在合并之前重塑 DT2,如下所示。我们还需要一步将计数更改为 A、B、C:

    merge(DT1, dcast(DT2[, -c(3:6)], iso + year + Val ~ name),
          by = c("iso", "year", "Val"))
    # Using 'year' as value column. Use 'value.var' to override
    # Aggregate function missing, defaulting to 'length'
    #    iso year Val C.x D  E  F A B C.y
    # 1: GRC 2001   1  NA 3 NA NA 0 0   3
    # 2: GRC 2002   1  NA 3 NA NA 2 1   0
    # 3: NLD 2001   1  NA 1 NA NA 2 1   0
    # 4: NLD 2002   1  NA 2 NA NA 1 2   0
    

    【讨论】:

    • 您可以通过在dcast 中使用自定义fun.aggregate 使额外的列成为实际字母,例如使用dt2_wd &lt;- dcast(dt2, iso + year + Val ~ name, value.var = 'name', fun.aggregate = function(x) x[1]) 然后merge(dt1, dt2_wd, by = c("iso", "year", "Val")) 给出问题中显示的输出(行顺序和最后一列名称除外)
    猜你喜欢
    • 2018-02-19
    • 1970-01-01
    • 2021-02-23
    • 2017-04-12
    • 2021-11-28
    • 1970-01-01
    • 2023-02-20
    • 2015-08-17
    • 1970-01-01
    相关资源
    最近更新 更多