R匹配两个以逗号分隔的字符串

时间:2015-02-18 17:53:59

标签: regex r pattern-matching match

我正在尝试找到一种优雅的方法来查找数据框中以下两个字符列之间的匹配项。复杂的部分是任一字符串都可以包含以逗号分隔的列表,如果一个列表的成员与另一个列表的任何成员匹配,那么整个条目将被视为匹配。我不确定我是如何解释这一点的,所以这里是样本数据和输出:

ALT1:

  • AT
  • A
  • G
  • CGTCC,AT
  • CGC

ALT2:

  • AA
  • A
  • GG
  • AT,GGT
  • CG

每行预期匹配:

  • 第1行=无
  • 第2行= A
  • 第3行=无
  • 第4行= AT
  • 第5行=无

非工作解决方案:

首次尝试:按所需列合并整个数据框,然后匹配上面显示的alt列:

match1 = data.frame(merge(vcf.df, ref.df, by=c("chr", "start", "end",  "ref")))
matches = unique(match1[unlist(sapply(match1$Alt1 grep, match1$Alt2, fixed=TRUE)),])

第二种方法,使用VariantAnnoatation / Granges中的findoverlaps功能:

findoverlaps(ranges(vcf1), ranges(vcf2)) 

任何建议都将不胜感激!谢谢!

解决方案 感谢@Marat Talipov在下面的回答,以下解决方案可以比较两个以逗号分隔的字符串:

> ##read in edited kaviar vcf and human ref
> ref <-     readVcfAsVRanges("ref.vcf.gz", humie_ref)
Warning message:
In .vcf_usertag(map, tag, ...) :
  ScanVcfParam ‘geno’ fields not present: ‘AD’

> ##rename chromosomes to match with vcf files
> ref <- renameSeqlevels(ref, c("1"="chr1"))

> ##################################
> ## Gather VCF files to process  ## 
> ##################################
> ##data frame *.vcf.gz files in directory path
> vcf_path <- data.frame(path=list.files(vcf_dir, pattern="*.vcf.gz$",  full=TRUE))

> ##read in everything but sample data for speediness
> vcf_param = ScanVcfParam(samples=NA)
> vcf <- readVcfAsVRanges("test.vcf.gz", humie_ref, param=vcf_param)

> #################
> ## Match SNP's ##
> #################
> ##create data frames of info to match on
> vcf.df = data.frame(chr =as.character(seqnames(vcf)), start = start(vcf),     end = end(vcf), ref = as.character(ref(vcf)), 
+                     alt=alt(vcf), stringsAsFactors=FALSE)
> ref.df = data.frame(chr =as.character(seqnames(ref)), start =     start(ref), end = end(ref), 
+                     ref = as.character(ref(ref)), alt=alt(ref),     stringsAsFactors=FALSE)
> 
> ##merge based on all positional fields except vcf
> col_match = data.frame(merge(vcf.df, ref.df, by=c("chr", "start", "end", "ref")))

> library(stringi)
> ##split each alt column by comma and bind together
> M1 <- stri_list2matrix(sapply(col_match$alt.x,strsplit,','))
> M2 <- stri_list2matrix(sapply(col_match$alt.y,strsplit,','))
> M <- rbind(M1,M2)

> ##compare results
> result <- apply(M,2,function(z) unique(na.omit(z[duplicated(z)])))

> ##add results column to col_match df for checking/subsetting
> col_match$match = result
> head(col_match)
   chr    start      end ref alt.x alt.y match
1 chr1 39998059 39998059   A     G     G     G
2 chr1 39998059 39998059   A     G     G     G
3 chr1 39998084 39998084   C     A     A     A
4 chr1 39998084 39998084   C     A     A     A
5 chr1 39998085 39998085   G     A     A     A
6 chr1 39998085 39998085   G     A     A     A

3 个答案:

答案 0 :(得分:2)

如果输入列表的长度相等,并且您希望以成对方式比较列表元素,则可以使用此解决方案:

library(stringi)

M1 <- stri_list2matrix(sapply(Alt1,strsplit,','))
M2 <- stri_list2matrix(sapply(Alt2,strsplit,','))
M <- rbind(M1,M2)

result <- apply(M,2,function(z) unique(na.omit(z[duplicated(z)])))

示例输入:

Alt1 <- list('AT','A','G','CGTCC,AT','CGC','GG,CC')
Alt2 <- list('AA','A','GG','AT,GGT','CG','GG,CC')

输出:

# [[1]]
# character(0)
# 
# [[2]]
# [1] "A"
# 
# [[3]]
# character(0)
# 
# [[4]]
# [1] "AT"
# 
# [[5]]
# character(0)
# 
# [[6]]
# [1] "GG" "CC"

答案 1 :(得分:1)

你可以这样做:

Alt1 <- list('AT','A','G',c('CGTCC','AT'),'CGC')
Alt2 <- list('AA','A','GG',c('AT','GGT'),'CG')
# make sure you change the lists within in the lists into vectors

matchlist <- list()
for (i in 1:length(Alt1)){
  matchlist[[i]] <- ifelse(Alt1[[i]] %in% Alt2[[i]], 
                           paste("Row",i,"=",c(Alt1[[i]],Alt2[[i]])[duplicated(c(Alt1[[i]],Alt2[[i]]))],sep=" "),
                           paste("Row",i,"= none",sep=" ")) 
}
print(matchlist)

答案 2 :(得分:1)

使用stringi软件包,您可以使用Marat答案中的Alt1Alt2数据执行此类操作。

library(stringi)

f <- function(x, y) {
    ssf <- stri_split_fixed(c(x, y), ",", simplify = TRUE)
    if(any(sd <- stri_duplicated(ssf))) ssf[sd] else NA_character_
}

Map(f, Alt1, Alt2)
# [[1]]
# [1] NA
# 
# [[2]]
# [1] "A"
# 
# [[3]]
# [1] NA
# 
# [[4]]
# [1] "AT"
# 
# [[5]]
# [1] NA
# 
# [[6]]
# [1] "GG" "CC"

或者在基础R中,我们可以使用scan()用逗号分隔字符串。

g <- function(x, y, sep = ",") {
    s <- scan(text = c(x, y), what = "", sep = sep, quiet = TRUE)
    s[duplicated(s)]
}
Map(g, Alt1, Alt2)