如何从字符字符串中提取数字?

6

I have a dataframe like this:

    > dns1
               variant_id         gene_id pval_nominal
21821  chr1_165656237_T_C_b38 ENSG00000143149  1.24119e-05
21822 chr1_165659346_C_CA_b38 ENSG00000143149  1.24119e-05
21823  chr1_165659350_A_G_b38 ENSG00000143149  1.24119e-05
21824  chr1_165659415_A_G_b38 ENSG00000143149  1.24119e-05
21825  chr1_165660430_T_C_b38 ENSG00000143149  1.24119e-05
21826  chr1_165661135_T_G_b38 ENSG00000143149  1.24119e-05
21827  chr1_165661238_C_T_b38 ENSG00000143149  1.24119e-05
...

我希望删除第二列(variant_id)中的所有字符,并提取第二个数字,使其看起来像这样:
165656237
165659346
165659350
165659415
165660430
165661135
165661238
...

我尝试了这个:
dns1$variant_id <- gsub('[^0-9.]', '', dns1$variant_id)

但是使用上述命令我得到了这个结果:
> dns1
      variant_id         gene_id pval_nominal
21821    116565623738 ENSG00000143149  1.24119e-05
21822    116565934638 ENSG00000143149  1.24119e-05
21823    116565935038 ENSG00000143149  1.24119e-05
21824    116565941538 ENSG00000143149  1.24119e-05
...

这将匹配 variant_id 列中的所有数字,我需要得到 16565623738 而不是 116565623738。那么问题是如何仅匹配第二个数字?


1
当我运行 gsub('_(.*)','', 'chr1_165656237_T_C_b38') 时,我得到的结果是 "chr1"。这不是你想要的,但我没有得到你报告的结果。 - Joseph Clark McIntyre
1
请确保您分享了数据的 dput() 或其他我们可以复制/粘贴到 R 中的内容。了解数据的确切内容和存储方式非常重要。此外,请确保这是可重现的。当我运行代码时,我也会得到不同的结果。您一定有遗漏某些东西。 - MrFlick
6个回答

9

您可以使用

dns1$variant_id <- sub('^[^_]*_(\\d+).*', '\\1', dns1$variant_id)

查看正则表达式演示

细节

  • ^ - 字符串的开头
  • [^_]* - 0个或多个非_字符
  • _ - 下划线
  • (\\d+) - 第一组:一个或多个数字
  • .* - 字符串的其余部分。

sub函数将仅在每个字符串上执行单个搜索和替换操作,替换中的\1反向引用将放回组1中的内容。

在线R演示:

variant_id <- c("chr1_165656237_T_C_b38", "chr1_165659346_C_CA_b38")
dns1 <- data.frame(variant_id)
dns1$variant_id <- sub('^[^_]*_(\\d+).*', '\\1', dns1$variant_id)
dns1
##=> variant_id
## 1  165656237
## 2  165659346

5
我相信你可以按以下方式获得数字:
gsub(".*?_([[:digit:]]+)_.*", "\\1", dns1$variant_id)

2
这里有一个使用stringr的选项:
library(stringr)

df <-
  data.frame(variant_id = c("chr1_165656237_T_C_b38",
                            "chr1_165659346_C_CA_b38",
                            "chr1_165659350_A_G_b38",
                            "chr1_165659415_A_G_b38",
                            "chr1_165660430_T_C_b38",
                            "chr1_165661135_T_G_b38",
                            "chr1_165661238_C_T_b38"))

df$variant_id_extract <-
  str_replace(df$variant_id, "^.+_(\\d+)_.+$", "\\1")

df
#>                variant_id variant_id_extract
#> 1  chr1_165656237_T_C_b38          165656237
#> 2 chr1_165659346_C_CA_b38          165659346
#> 3  chr1_165659350_A_G_b38          165659350
#> 4  chr1_165659415_A_G_b38          165659415
#> 5  chr1_165660430_T_C_b38          165660430
#> 6  chr1_165661135_T_G_b38          165661135
#> 7  chr1_165661238_C_T_b38          165661238

1
这里有一个超级hacky的解决方案,它同时使用了gsub和str_replace(来自stringr)。我相信有更好的解决方案,而且这需要variant_id始终以chr1_开头,这可能不太公平。
dns1$variant_id <- gsub('_(.*)','', str_replace(dns1$variant_id, 'chr1_',''))

1

您可以使用

dns$variant_id_new <- sapply(strsplit(as.character(dns$variant_id), "_"), unlist)[2,]

逻辑上,这首先通过 _ 分割所有的 variant_id 字符串。使用 sapply(,unlist) 将其转换为矩阵,然后我们取第二行 (第二个变量)。


0

使用utils::strcapture,我们可以提取变异体ID的所有部分,包括基因组位置。

# example input
x <- c("chr1_165656237_T_C_b38", "chr1_165659346_C_CA_b38")

# get pattern for each part
pattern <- "(.*?)_([[:digit:]]+)_([A-Z]+)_([A-Z]+)_(b[0-9]+)"

# empty dataframe with columns to match after split
proto <- data.frame(chrom = character(), position = integer(), 
                    allele1 = character(), allele2 = character(), build = character())

# extract
strcapture(pattern, x, proto)
#   chrom  position allele1 allele2 build
# 1  chr1 165656237       T       C   b38
# 2  chr1 165659346       C      CA   b38

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接