在数据框中创建新列,其条目取决于另一个数据框中的多个列

时间:2014-05-30 01:57:38

标签: r

我想在我的数据集中创建新列,其值由另一个数据集中的值确定,但它并不像一列中的值是另一列中值的函数那么简单。这是一个例子:

 >df1  
      chromosome position
1              1        1
2              1        2
3              1        4
4              1        5
5              1        7
6              1       12
7              1       13
8              1       15
9              1       21
10             1       23
11             1       24
12             2        1
13             2        5
14             2        7
15             2        8
16             2       12
17             2       15
18             2       18
19             2       21
20             2       22

>df2
  chromosome segment_start segment_end segment.number
1          1             1           5            1.1
2          1             6          20            1.2
3          1            21          25            1.3
4          2             1           7            2.1
5          2             8          16            2.2
6          2            18          22            2.3

我想在df1中创建一个名为'segment'的新列,并且segment中的值将由哪个段(由'segment_start','segment_end'和来自df2的'chromosome'确定)确定在'位置'属于。例如,在df1,第7行,位置= 13,染色体= 1。因为13在6到20之间,我假设的“段”列中的条目将是df2的第2行的1.2,因为13位于该行的segment_start和segment_end之间(分别为6和20),以及'染色体'来自df1第7行的值为1,正如df2第2行中的“染色体”为1。

df1中的每一行都属于df2中描述的一个段;也就是说,它与一个片段位于同一染色体上,并且其“位置”是> = segment_start和< = segment_end。我希望将这些信息输入df1,因此它表示每个位置属于哪个段。

我正在考虑使用if函数,并以:

开头
if(df1$position>=df2$segment_start & df1$position<=df2$segment_end & df1$chromosome==df2$chromosome) df1$segment<-df2$segment.number

但我不确定这种方式是否可行。如果没有其他可能代码可以帮助说明我正在尝试做什么。基本上,我想通过它的位置和染色体将每一行匹配到df2中的一个段。感谢。

3 个答案:

答案 0 :(得分:2)

这似乎是滚动连接。您可以将data.table用于此

require(data.table)
DT1 <- data.table(df1, key = c('chromosome','position'))
DT2 <- data.table(df2, key = c('chromosome','section_start'))
# this will perform the join you want (but retain all the 
# columns with names names of DT2)
# DT2[DT1, roll=TRUE]
# which is why I have renamed and subset here) 
DT2[DT1, roll=TRUE][ ,list(chromosome,position = segment_start,segment.number)]
#     chromosome position segment.number
# 1:           1        1            1.1
# 2:           1        2            1.1
# 3:           1        4            1.1
# 4:           1        5            1.1
# 5:           1        7            1.2
# 6:           1       12            1.2
# 7:           1       13            1.2
# 8:           1       15            1.2
# 9:           1       21            1.3
# 10:          1       23            1.3
# 11:          1       24            1.3
# 12:          2        1            2.1
# 13:          2        5            2.1
# 14:          2        7            2.1
# 15:          2        8            2.2
# 16:          2       12            2.2
# 17:          2       15            2.2
# 18:          2       18            2.3
# 19:          2       21            2.3
# 20:          2       22            2.3

答案 1 :(得分:1)

您真的需要查看Bioconductor的GenomicRanges包。它提供了适合您的用例的数据结构。

首先,我们创建GRanges个对象:

gr1 <- with(df1, GRanges(chromosome, IRanges(position, width=1L)))
gr2 <- with(df2, GRanges(chromosome, IRanges(segment_start, segment_end),
                         segment.number=segment.number))

然后我们找到重叠并进行合并:

hits <- findOverlaps(gr1, gr2)
gr1$segment[queryHits(hits)] <- gr2$segment.number[subjectHits(hits)]

答案 2 :(得分:0)

我将假设df2中的区域不重叠,连续且完整(不会遗漏df1中的任何位置)。每当我尝试时,我似乎都会这样做,所以这是我最新的想法。

首先,确保染色体是两个数据集中的一个因素

df1$chromosome<-factor(df1$chromosome)
df2$chromosome<-factor(df2$chromosome)

现在我想打开chr / pos到一个通用位置,我会用

做到这一点
ends<-with(df2, tapply(segment_end, chromosome, max))
offset<-head(c(0,cumsum(ends)),-1)
names(offset)<-names(ends)

这为所有染色体上的所有位置分配了唯一的位置值,并且它跟踪了这个新系统中每条染色体开头的偏移量。现在我们将根据df2

中的数据构建翻译函数
seglookup <- approxfun(with(df2, offset[chromosome]+segment_start), 1:nrow(df2),
    method="constant", rule=2)

我们使用approxfun在每个片段的遗传位置空间中找到正确的间隔。现在我们在df1

上使用此功能
segid <- with(df1, seglookup(offset[chromosome]+position))

现在我们为每个职位提供了正确的ID。我们可以通过合并数据并查看结果来验证这一点

cbind(df1, df2[segid,-1])

   chromosome position segment_start segment_end segment.number
1           1        1             1           5            1.1
2           1        2             1           5            1.1
3           1        4             1           5            1.1
4           1        5             1           5            1.1
5           1        7             6          20            1.2
6           1       12             6          20            1.2
7           1       13             6          20            1.2
8           1       15             6          20            1.2
9           1       21            21          25            1.3
10          1       23            21          25            1.3
11          1       24            21          25            1.3
12          2        1             1           7            2.1
13          2        5             1           7            2.1
14          2        7             1           7            2.1
15          2        8             8          16            2.2
16          2       12             8          16            2.2
17          2       15             8          16            2.2
18          2       18            18          22            2.3
19          2       21            18          22            2.3
20          2       22            18          22            2.3

所以看起来我们没事。