簡體   English   中英

檢查一個 dataframe 的列值是否在第二個 dataframe 的其他兩列之間(范圍)

[英]Check if column value from one dataframe is in between (range) of two other columns of second dataframe

我有兩個不同大小的數據框:

df1<-data.frame(Chr = c(1, 1,2,3,4),
                Start = c(15,120, 210,210,450),
                End = c(15,130, 210,210,450),
                Gene=c("gene1","gene2","gene3","gene3","gene3"),
                sample_id=c("ss6","ss7","ss9","ss9","ss10"))
      
  df2 <- data.frame(Chr = c(1, 1,3),
                    Start = c(10,100, 200),
                    End = c(50,200, 250),
                    Gene=c("gene1","gene2","gene3"),
                    sample_id=c("ss1","ss1","ss1"))

我想從 df1 獲取 Start 並檢查它是否在 df2 的 Start-End 范圍內,同時確保 Chr 相同(sample_id 不必匹配)。 如果是,則最好使用 df2$sample_id 向 df1 添加一列,但如果不可能,則為 YES(或 NA 表示不匹配)。 它類似於這個問題,但我還需要匹配 'Chr' Only checking range

它也類似於這個問題,我知道它應該更容易,因為我不想匹配相應的行Check if column value is in between (range) of two other column values

我努力了:

df1 %>%
  mutate(no_coverage_in = case_when(df2$Start <= Start  & df2$End >=Start & Chr == df2$Chr ~ df2$sample_id ))

但它抱怨

較長的 object 長度不是較短的 object 長度的倍數

這是你想要的嗎?

Given data frames
> df1
  Chr Start End  Gene sample_id
1   1    15  15 gene1       ss6
2   1   120 130 gene2       ss7
3   2   210 210 gene3       ss9
4   3   210 210 gene3       ss9
5   4   450 450 gene3      ss10
> df2
  Chr Start End  Gene sample_id
1   1    10  50 gene1       ss1
2   1   100 200 gene2       ss1
3   3   200 250 gene3       ss1

vec2 <- c()
for (k in 1:nrow(df1)) {
  if (df1$Chr[k] %in% df2$Chr)  {
    vec <- which(df2$Chr==df1$Chr[k])  
    for (m in 1:length(vec)) {
        if (df1$Start[k]<df2$Start[m] &df1$End[k]<df2$End[m]) {
          vec2[k] <- "Yes"
          
        }else{
          vec2[k] <- "No"
        }
    }
  }else{
    vec2[k] <- "No"
  }
}
df1$Results <- vec2

output

> df1
  Chr Start End  Gene sample_id Results
1   1    15  15 gene1       ss6     Yes
2   1   120 130 gene2       ss7      No
3   2   210 210 gene3       ss9      No
4   3   210 210 gene3       ss9      No
5   4   450 450 gene3      ss10      No

我相信這會給你你想要的結果:


df1 %>%
  left_join(df2 %>% rename_at(vars(Start, End, sample_id), paste0, "_2")) %>%
  mutate(sample_id_new = case_when(Start < End_2 & Start > Start_2 ~ sample_id_2)) %>% 
  select(Chr, Start, End, Gene, sample_id, sample_id_new)

Output:

  Chr Start End  Gene sample_id sample_id_new
1   1    15  15 gene1       ss6           ss1
2   1   120 130 gene2       ss7           ss1
3   2   210 210 gene3       ss9          <NA>
4   3   210 210 gene3       ss9           ss1
5   4   450 450 gene3      ss10          <NA>

您可以編寫一個小的FUN函數來檢查df1的每一行,並將其放入循環遍歷其行的lapply中。

FUN <- \(x, y) {
  rng <- df1[x, 2] >= y[, 2] & df1[x, 3] < y[, 3]
  chr <- df1[x, 1] == y[, 1]
  if (any(rng & chr)) df2[which(rng), 5] else NA
}

df1 <- transform(df1, match=unlist(lapply(seq.int(nrow(df1)), FUN, df2)))
df1
#   Chr Start End  Gene sample_id match
# 1   1    15  15 gene1       ss6   ss1
# 2   1   120 130 gene2       ss7   ss1
# 3   2   210 210 gene3       ss9  <NA>
# 4   3   210 210 gene3       ss9   ss1
# 5   4   450 450 gene3      ss10  <NA>

筆記:

我使用新的速記符號在 R>4.1.* 中創建函數。 對於較舊的 R 版本,請使用FUN <- function(x, y)或更新 R 而不是FUN <- \(x, y)

這是一個建議。

  df1$match= sapply( 1:nrow(df1) , 
                     function(x)   
                          any(  df1[x, 'Chr']==df2[, 'Chr'] &
                                df1[x , 'Start'] <= df2[ , 'End'] & 
                                df1[x , 'Start'] >= df2[ , 'Start'] ))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM