寻找数据帧值的范围

时间:2016-07-18 09:14:34

标签: r dataframe range

我有2个数据帧:

> access
     V1     V2     V3
1 chr10 136122 136533
2 chr10 179432 179769
3 chr10 182988 183371
4 chr10 224234 224489
5 chr10 237693 237958

> peaks
     V1     V2     V3
1 chr10 126122 126533
2 chr10 179450 179730
3 chr10 182788 183350
4 chr10 224244 224500
5 chr10 237695 237950

两个数据帧中的色域V2和V3是开始结束区域(范围)。我希望将这些行保留在peaks数据框中,access$V1 == peaks$V1 AND位于access数据帧的范围(或区域)内。例如,新数据框将类似于:peaks数据帧的

  • access数据框中不存在第1行区域,因此会为其分配 U 类别。

  • peaks的第二行属于access数据框(第二行)的给定范围,并将分配类别 B

  • peaks的第3行并未完全落入该区域,但它与access第3行中的某个区域重叠,为此,我将指定类别 A

  • peaks的第4行在访问的第4行中的区域结尾之后的第11行也没有完全重叠,这也将属于 A 类别

  • 第5行属于该区域,因此属于 B 类别。

预期输出:

> newdf   
     V1     V2     V3 V4
1 chr10 126122 126533  U
2 chr10 179450 179730  B
3 chr10 182788 183350  A
4 chr10 224244 224500  A
5 chr10 237695 237950  B

以下是输入数据帧的输入:

> dput(peaks)
structure(list(V1 = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "chr10", class = "factor"), 
    V2 = c(126122L, 179450L, 182788L, 224244L, 237695L), V3 = c(126533L, 
    179730L, 183350L, 224500L, 237950L)), .Names = c("V1", "V2", 
"V3"), class = "data.frame", row.names = c(NA, -5L))

> dput(access)
    structure(list(V1 = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "chr10", class = "factor"), 
        V2 = c(136122L, 179432L, 182988L, 224234L, 237693L), V3 = c(136533L, 
        179769L, 183371L, 224489L, 237958L)), .Names = c("V1", "V2", 
    "V3"), class = "data.frame", row.names = c(NA, -5L))

修改

我的新访问权限df看起来像这样,现在我还想在我的最终输出df中附加最后一列:

> access
     V1     V2     V3  V4
1 chr10 136122 136533  found
2 chr10 179432 179769  notFound
3 chr10 182988 183371  found
4 chr10 224234 224489  found
5 chr10 237693 237958  notFound

所以现在还有一个额外的条件,即如果访问中的行落在峰值范围内,那么还会在最后一个df的新列中附加V4中的值,如果找不到某个区域,则默认为{{1} }。因此,最终输出将是:

notFound

此处> newdf V1 V2 V3 V4 V5 1 chr10 126122 126533 U notFound 2 chr10 179450 179730 B notFound 3 chr10 182788 183350 A found 4 chr10 224244 224500 A found 5 chr10 237695 237950 B notFound 中的值为notFound,因为未找到此区域,在其余情况下,我们从修改后的访问df中获取V5中的值。

4 个答案:

答案 0 :(得分:1)

如果速度是一个问题,链接的data.table解决方案可能会更好,但它也可以在dplyr中实现,但可能要慢得多:

library(dplyr)
names(access)[2:3] <- c('start', 'end')

bind_cols(peaks[-1], access) %>%
  rowwise() %>% 
  mutate(V4 = if_else(all(V2:V3 %in% start:end), 'B',
                      if_else(any(V2:V3 %in% start:end), 'A',
                              'U')))

结果:

Source: local data frame [5 x 6]
Groups: <by row>

# A tibble: 5 x 6
      V2     V3     V1  start    end    V4
   <int>  <int> <fctr>  <int>  <int> <chr>
1 126122 126533  chr10 136122 136533     U
2 179450 179730  chr10 179432 179769     B
3 182788 183350  chr10 182988 183371     A
4 224244 224500  chr10 224234 224489     A
5 237695 237950  chr10 237693 237958     B

答案 1 :(得分:1)

尽管它还有很长的路要走。但它给出了预期的结果。

library(dplyr)
df<-cbind(peaks,access) #merging both df
colnames(df)<-c("pV1","pV2","pV3","aV1","aV2","aV3")
df<-df[c(which(df$pV1==df$aV1)),] # selecting rows with pV1=aV1
# creating U, A, B
U1<-df%>%
   filter(pV2<aV2 & pV3<aV2)%>%
   mutate(V4="U")
U2<-df%>%
  filter(pV2>aV3 & pV3>aV3)%>%
  mutate(V4="U")
B<-df%>%
 filter(pV2>aV2 & pV3<aV3)%>%
   mutate(V4="B")
A1<-df%>%
   filter(pV2>aV2 & pV3>aV3)%>%
   mutate(V4="A")
A2<-df%>%
   filter(pV2<aV2 & pV3<aV3 & pV3>aV2)%>%
   mutate(V4="A")
#merging U, A and B into newdf
newdf<-arrange(rbind(U1,U2,B,A1,A2),pV2)
newdf<-newdf[,-c(4:6)]
newdf
    pV1    pV2    pV3 V4
1 chr10 126122 126533  U
2 chr10 179450 179730  B
3 chr10 182788 183350  A
4 chr10 224244 224500  A
5 chr10 237695 237950  B

答案 2 :(得分:1)

使用foverlaps功能可以使用以下语句完成:

setkey(setDT(access),V1,V2,V3)
setkey(setDT(peaks),V1,V2,V3)

access[,V4:= ifelse(!is.na(foverlaps(peaks, access, type="within", which=TRUE)$yid),"B",ifelse(!is.na( foverlaps(peaks, access, type="any", which=TRUE)$yid),"A","U"))]

它的运作方式如下:

  1. 我首先使用#34;&#34;键入以确定是否存在精确重叠(因此,如果任何匹配的访问范围中包含范围。如果是这种情况,那么&#34; B&#34;
  2. 如果不是这种情况,我会使用&#34; any&#34;确定我们是否有任何实际上识别具有部分重叠的值的重叠,因为在前一步骤中排除了具有精确重叠的值。这些值得到一个&#34; A&#34;
  3. 其他人得到了一个&#34; U&#34;

答案 3 :(得分:0)

这是另一个(直接)解决方案,它使用最近实现的非equi连接,并在当前开发版本的data.table,v1.9.7中提供。请参阅安装说明here

require(data.table) # v1.9.7+
setDT(access)
setDT(peaks)[, V4 := "U"]                              # no overlap
peaks[access, V4 := "A", on=.(V1, V2 <= V3, V3 >= V2)] # any overlap
peaks[access, V4 := "B", on=.(V1, V2 >= V2, V3 <= V3)] # completly within
#       V1     V2     V3 V4
# 1: chr10 126122 126533  U
# 2: chr10 179450 179730  B
# 3: chr10 182788 183350  A
# 4: chr10 224244 224500  A
# 5: chr10 237695 237950  B

peaks添加一个新列,全部是&#34; U&#34;。然后替换那些与&#34; A&#34;有任何重叠的行。这将包含所有在&#34; 内完全&#34;的行。然后再次执行条件连接,但这次只是完全在内,并用&#34; B&#34;替换。

请注意,foverlaps()解决方案也可以正常工作(它也来自data.table包)。但是新的非equi连接符合[.data.table语法,允许在加入时聚合/添加/更新cols