如果知道范围,在R中填充 Dataframe

sd2nnvve  于 2023-02-26  发布在  其他
关注(0)|答案(4)|浏览(144)

我正在寻找类似于bedtools subtract但有 Dataframe 的东西。
例如,假设我有一个 Dataframe 范围:

Start End Value
0 100 P

我还有另一个 Dataframe ,它是排序的:

Start End Value
10 25 A
50 63 B

有没有一种方法可以像这样填充这个:

Start End Value
 0   9 P1
10  25 A
26  49 P2
50  63 B
64 100 P3

填充P1、P2和P3标签以填充第2个 Dataframe ,从而覆盖整个值范围。
我尝试使用Dplyr的Lag函数并手动添加填充值,但考虑到范围可以根据基因组特征的长度(包括起始和结束坐标)而改变,我希望此范围填充是自动的。
谢谢大家!
例如,这是数据的一个小子集:

data_range<- data.frame(start=0, end=100, value="P")

tofill_range<- data.frame(start=c(15, 51, 70),end = c(39, 62, 79), value = c("A","B","C"))
q43xntqr

q43xntqr1#

以R为底:

all_ranges <- function(df1, df2){
  a <- sort(c(t(df1[-3]), t(df2[-3]), t(df2[-3]) + c(-1,1)))
  b <- data.frame(t(matrix(a,2)))
  d <- merge(df2, setNames(b, names(df1)[-3]), all = TRUE)
  replace(d, is.na(d), paste0(df1[,3], seq(sum(is.na(d)))))
}

data_range<- data.frame(start=0, end=100, value="P")

tofill_range<- data.frame(start=c(15, 51, 70),end = c(39, 62, 79), value = c("A","B","C"))

all_ranges(data_range, tofill_range)
#>   start end value
#> 1     0  14    P1
#> 2    15  39     A
#> 3    40  50    P2
#> 4    51  62     B
#> 5    63  69    P3
#> 6    70  79     C
#> 7    80 100    P4

创建于2023年2月23日,使用reprex v2.0.2

vqlkdk9b

vqlkdk9b2#

使用dplyr(对于consecutive_id,〉=v1.1.0
使用between获取缺失的范围

library(dplyr)

ranges <- rowSums(apply(tofill_range[,1:2], 1, function(x) 
  between(seq(data_range$start, data_range$end), x[1], x[2])))
as_tibble(cbind(ranges, grp = consecutive_id(ranges), 
            val = seq(data_range[,1], data_range[,2]))) %>% 
  group_by(grp) %>% 
  filter(ranges == 0) %>% 
  summarize(start = first(val), 
            end = last(val), 
            value = paste0(data_range$value, cur_group_id())) %>% 
  select(-grp) %>% 
  bind_rows(., tofill_range) %>% 
  arrange(start)
# A tibble: 7 × 3
  start   end value
  <dbl> <dbl> <chr>
1     0    14 P1   
2    15    39 A    
3    40    50 P2   
4    51    62 B    
5    63    69 P3   
6    70    79 C    
7    80   100 P4
iugsix8n

iugsix8n3#

这里有一种方法可以计算一个data.frame的范围,只需要使用'dplyr'。对于你的第二个例子,我重命名了列。我们可以做更多的工作,使它可以与任何列名一起工作。

library(dplyr)

calc_range <- function(df1, df2) {
  df3 <- df2 %>% 
    transmute(start = End + 1,
              End = Start - 1) %>% 
    rename(Start = start)
  
  start_df <- bind_rows(df1, df2, df3)
  
  start_df %>% 
    select(!Value) %>% 
    unlist %>% 
    sort %>% 
    matrix(ncol = 2, byrow = TRUE) %>% 
    data.frame() %>% 
    rename(Start = X1, End = X2) %>% 
    left_join(start_df, by = c("Start", "End")) %>% 
    mutate(Value = ifelse(is.na(Value) | Value == "P",
                          paste0("P", cumsum(is.na(Value) | Value == "P")),
                          Value)) %>% 
    arrange(Start)
}

# Test 1

dfa <- tribble(
  ~Start, ~End, ~Value,
  0, 100, "P"
)

dfb <- tribble(~Start, ~End, ~Value,
               10, 25, "A",
               50, 63, "B")

calc_range(dfa, dfb)
#>   Start End Value
#> 1     0   9    P1
#> 2    10  25     A
#> 3    26  49    P2
#> 4    50  63     B
#> 5    64 100    P3

# Test 2 
data_range <- data.frame(Start=0, End=100, Value="P")

tofill_range <- data.frame(Start=c(15, 51, 70),
                          End = c(39, 62, 79),
                          Value = c("A","B","C"))

calc_range(data_range, tofill_range)
#>   Start End Value
#> 1     0  14    P1
#> 2    15  39     A
#> 3    40  50    P2
#> 4    51  62     B
#> 5    63  69    P3
#> 6    70  79     C
#> 7    80 100    P4

创建于2023年2月23日,使用reprex v2.0.2

hmae6n7t

hmae6n7t4#

“IRanges”是非常适合此任务的软件包:

library(IRanges)

r1 = IRanges(start = 0, end = 100, names = "P")
r2 = IRanges(start = c(10, 50), end = c(25, 63), names = c("A", "B"))

# find gaps
dif = setdiff(r1, r2)
names(dif) = sprintf("%s%d", names(r1), seq_len(length(dif)))

# merge and sort
ans = sort(c(r2, dif))

as.data.frame(ans)
#  start end width names
#1     0   9    10    P1
#2    10  25    16     A
#3    26  49    24    P2
#4    50  63    14     B
#5    64 100    37    P3

相关问题