在另一个data.table中的值基础上填充一个data.table。

9

我对 data.table 完全不熟悉,但是我想用它来解决我的问题,因为我感觉它比“常规”的数据框快1000倍。

这是我的问题:

我的情况:

有两个类似于 dt1dt2 的数据表:

dt1 <- data.table(SID=paste0("S", 1:15), Chromo=rep(1:3, e=5), PP=rep(1:5, 3), P1=0, P2=0, P3=0)
set.seed(17)
dt2 <- data.table(PID=rep(paste0("P", 1:3), c(2, 6, 3)), Chr=c(1, 3, 1, 1, 2, 3, 3, 3, 2, 2, 3), start= c(1, 1, 1, 4, 2, 1, 2, 4, 2, 4, 2), end=c(3, 4, 2, 5, 4, 1, 3, 5, 3, 5, 5), val=rnorm(11))

我想要的:

根据dt2 [,PID]和右侧行,基于dt1 [,Chromo] = dt2 [,Chr]dt1 [,PP]dt2 [,start]dt2 [,end]之间,将dt2 [,val]填充到右列的dt1中。

我现在做的事情:(说实话,这让我感到很不自豪...)

# preparing the tables, computing dt1 rows indices
dt2[, numcol:=(1:ncol(dt1))[match(dt2[,PID], colnames(dt1))]]
setkey(dt2, Chr, start, end)
setkey(dt1, Chromo, PP)
ind_start <- dt1[dt2[,.(Chr, start)], which=T]
ind_end <- dt1[dt2[,.(Chr, end)], which=T]
dt2[,c("ind_start", "ind_end"):=list(ind_start, ind_end)]

# and feeling I'm that close but can't conclude with `data.table` so doing this "lame" `for` loop with `data.frames`.......................
df1 <- as.data.frame(dt1)
df2 <- as.data.frame(dt2)
nr_seg <- nrow(df2)
for(i in 1:nr_seg){
    df1[df2[i,"ind_start"]:df2[i,"ind_end"], df2[i,"numcol"]] <- df2[i, "val"]
}

输入表格和所需输出(除了我想要一个data.table:

dt1
    # SID Chromo PP P1 P2 P3
 # 1:  S1      1  1  0  0  0
 # 2:  S2      1  2  0  0  0
 # 3:  S3      1  3  0  0  0
 # 4:  S4      1  4  0  0  0
 # 5:  S5      1  5  0  0  0
 # 6:  S6      2  1  0  0  0
 # 7:  S7      2  2  0  0  0
 # 8:  S8      2  3  0  0  0
 # 9:  S9      2  4  0  0  0
# 10: S10      2  5  0  0  0
# 11: S11      3  1  0  0  0
# 12: S12      3  2  0  0  0
# 13: S13      3  3  0  0  0
# 14: S14      3  4  0  0  0
# 15: S15      3  5  0  0  0

dt2
  # PID Chr start end         val
 # 1:  P2   1     1   2 -0.23298702
 # 2:  P1   1     1   3 -1.01500872
 # 3:  P2   1     4   5 -0.81726793
 # 4:  P3   2     2   3  0.25523700
 # 5:  P2   2     2   4  0.77209084
 # 6:  P3   2     4   5  0.36658112
 # 7:  P2   3     1   1 -0.16561194
 # 8:  P1   3     1   4 -0.07963674
 # 9:  P2   3     2   3  0.97287443
# 10:  P3   3     2   5  1.18078924
# 11:  P2   3     4   5  1.71653398

df1
   # SID Chromo PP          P1         P2        P3
# 1   S1      1  1 -1.01500872 -0.2329870 0.0000000
# 2   S2      1  2 -1.01500872 -0.2329870 0.0000000
# 3   S3      1  3 -1.01500872  0.0000000 0.0000000
# 4   S4      1  4  0.00000000 -0.8172679 0.0000000
# 5   S5      1  5  0.00000000 -0.8172679 0.0000000
# 6   S6      2  1  0.00000000  0.0000000 0.0000000
# 7   S7      2  2  0.00000000  0.7720908 0.2552370
# 8   S8      2  3  0.00000000  0.7720908 0.2552370
# 9   S9      2  4  0.00000000  0.7720908 0.3665811
# 10 S10      2  5  0.00000000  0.0000000 0.3665811
# 11 S11      3  1 -0.07963674 -0.1656119 0.0000000
# 12 S12      3  2 -0.07963674  0.9728744 1.1807892
# 13 S13      3  3 -0.07963674  0.9728744 1.1807892
# 14 S14      3  4 -0.07963674  1.7165340 1.1807892
# 15 S15      3  5  0.00000000  1.7165340 1.1807892  

1
你可以使用 foverlaps 方法。但是如何决定值应该放在哪个 Pi 列中呢? - Roland
1
@Roland,感谢你。我不知道这个函数,我会去看看的。至于“Pi”,在dt2PID列中的“Pi”必须与dt1中的列名匹配。 - Cath
2
您可能会发现这个问答是一个有用的起点。看起来您的“PP”列对应于该帖子中的“pos”列。我认为@Arun的“更新答案”非常好。 - Henrik
@Henrik,再次感谢,我确实在阅读所有的问答,是的,PP代表“物理位置”,Chr / Chromo代表“染色体”;-) - Cath
1
@CathG 我意识到我的措辞“可能是重复的”可能不太恰当。因此,我只是想以一种希望有所帮助的问答方式来表达我的指针。 - Henrik
1个回答

6
library(data.table)
dt1 <- data.table(SID=paste0("S", 1:15), Chromo=rep(1:3, e=5), PP=rep(1:5, 3), P1=0, P2=0, P3=0)
set.seed(17)
dt2 <- data.table(PID=rep(paste0("P", 1:3), c(2, 6, 3)), Chr=c(1, 3, 1, 1, 2, 3, 3, 3, 2, 2, 3), start= c(1, 1, 1, 4, 2, 1, 2, 4, 2, 4, 2), end=c(3, 4, 2, 5, 4, 1, 3, 5, 3, 5, 5), val=rnorm(11))

dt1[, PP1 := PP]
dt1[, c("P1", "P2", "P3") := NULL]


setkey(dt2, Chr, start, end)

setkey(dt1, Chromo, PP, PP1)

res <- foverlaps(dt1, dt2, type="within")
res[is.na(PID), PID := "P1"] #to ensure that dcast works if there is no match
res <- dcast.data.table(res, SID + Chromo + PP ~ PID, value.var = "val")
setkey(res, Chromo, PP)

#    SID Chromo PP          P1         P2        P3
# 1:  S1      1  1 -1.01500872 -0.2329870        NA
# 2:  S2      1  2 -1.01500872 -0.2329870        NA
# 3:  S3      1  3 -1.01500872         NA        NA
# 4:  S4      1  4          NA -0.8172679        NA
# 5:  S5      1  5          NA -0.8172679        NA
# 6:  S6      2  1          NA         NA        NA
# 7:  S7      2  2          NA  0.7720908 0.2552370
# 8:  S8      2  3          NA  0.7720908 0.2552370
# 9:  S9      2  4          NA  0.7720908 0.3665811
#10: S10      2  5          NA         NA 0.3665811
#11: S11      3  1 -0.07963674 -0.1656119        NA
#12: S12      3  2 -0.07963674  0.9728744 1.1807892
#13: S13      3  3 -0.07963674  0.9728744 1.1807892
#14: S14      3  4 -0.07963674  1.7165340 1.1807892
#15: S15      3  5          NA  1.7165340 1.1807892

感谢Roland的回答。不过我确实需要在现有的“NAs”处填充0(你可以使用setkey(res, Chromo, PP)进行排序),而且是的,我确实需要所有SID。 - Cath
1
对于精确的输出,您可以执行res <- foverlaps(dt1, dt2, type="within") ; res <- dcast.data.table(res, SID + Chromo + PP ~ PID, value.var = "val", fill = 0L)[, `NA` := NULL]。虽然不太美观。 - David Arenburg
@CathG 我已经更改了它,包括 S6 - Roland
@Roland 非常感谢您的编辑。我在处理真实数据时遇到了问题,使用dcast命令时收到警告:“缺少聚合函数,默认为'length'”,并且对于第4列到最后一列,在结果中只有1和0。 - Cath
这意味着你有重复的SID/Chromo/PP ID组合。你需要决定如何处理这种情况。一个可能的方法是用平均值聚合这些值。另一种方法是添加一个额外的列使ID组合唯一。 - Roland
@Roland;谢谢(再次)回答,我不应该有重复的SID-Chromo-PP-PID组合........我会解决这个问题! - Cath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接