R 在一组字符串中查找子字符串的频率
我有一个基因列表作为输入,其中每个基因都有一个标题,如>SomeText。 对于每个基因,我想找出字符串R 在一组字符串中查找子字符串的频率,r,perl,R,Perl,我有一个基因列表作为输入,其中每个基因都有一个标题,如>SomeText。 对于每个基因,我想找出字符串GTG的频率。(发生次数除以基因长度)。仅当字符串从位置1、4、7、10等(每个thids位置)开始时,才应对其进行计数 输出: Gene Frequency Gene1: 3 Gene2 6.3 .... Gene1: 0.00483091787439614 Gene2: 0 Gene3: 0.00302114803625378 我曾经想过这样的事情,但我现在不知道如何定义职位要求:
GTG
的频率。(发生次数除以基因长度)。仅当字符串从位置1、4、7、10等(每个thids位置)开始时,才应对其进行计数
输出:
Gene Frequency
Gene1: 3
Gene2 6.3
....
Gene1: 0.00483091787439614
Gene2: 0
Gene3: 0.00302114803625378
我曾经想过这样的事情,但我现在不知道如何定义职位要求:
freq <- sapply(gregexpr("GTG",x),function(x)if(x[[1]]!=-1) length(x) else 0)
freq好吧,你有一个R解。我已经在perl
中对一些东西进行了黑客攻击,因为您标记了它:
#!/usr/bin/env perl
use strict;
use warnings;
my $target = 'GTG';
local $/ = "\n>";
while ( <> ) {
my ($gene) = m/(Gene\d+)/;
my @hits = grep { /^$target$/ } m/ ( [GTCA]{3} ) /xg;
print "$gene: ".( scalar @hits), "\n";
}
我将您的字符串分解为3个元素列表,并寻找特别匹配的元素列表。(我没有除以长度,因为我不完全清楚这是字母中的实际字符串长度,还是其他度量)
包括长度匹配-我们需要捕获名称和字符串:
#!/usr/bin/env perl
use strict;
use warnings;
local $/ = "\n>";
while (<>) {
my ($gene, $gene_str) = m/(Gene\d+)\n([GTCA]+)/m;
my @hits = grep { /^GTG$/ } $gene_str =~ m/ ( [GTCA]{3} ) /xg;
print "$gene: " . @hits . "/". length ( $gene_str ), " = ", @hits / length($gene_str), "\n";
}
这里有一个不使用模式匹配的替代解决方案。这并不重要
use strict;
use warnings;
my $gene;
while ( my $line = <> ) {
if ( $line =~ /^>(.+)/ ) {
$gene = $1;
next;
}
chomp $line;
printf "%s: %s\n",
$gene,
( grep { $_ eq 'GTG' } split /(...)/, $line ) / length $line;
}
这基本上与索布里克的答案相似,但假设基因系包含正确的字符。它将基因字符串拆分为一个由三个字符组成的列表,并从字面上提取GTG
拆分的工作原理是滥用split
使用模式作为分隔符的事实,如果使用捕获组,它也将捕获分隔符。这里有一个例子
my @foo = split /(...)/, '1234567890';
p @foo; # from Data::Printer
__END__
[
[0] "",
[1] 123,
[2] "",
[3] 456,
[4] "",
[5] 789,
[6] 0
]
空元素通过grep
过滤掉。这可能不是最有效的方法,但它可以完成任务
您可以通过调用perl foo.pl可怕的大基因序列.file
来运行它。下面是使用stringi
的R中的一个想法
我们使用stri\u locate\u all\u fixed()
查找每个GTG
发生的开始
和结束
位置。然后我们创建一列条件
,测试开始
位置是否在1,4,7,10,13,16,19,22…
library(stringi)
library(dplyr)
data.frame(stri_locate_all_fixed(gene1, "GTG")) %>%
mutate(condition = start %in% seq(1, nchar(gene), 3))
其中:
# start end condition
#1 4 6 TRUE
如果你想将其概括为一系列基因,你可以这样做:
lst <- list(gene1, gene2, gene3)
res <- lapply(lst, function(x) {
data.frame(stri_locate_all_fixed(x, "GTG")) %>%
mutate(condition = start %in% seq(1, nchar(x), 3))
})
lapply(1:length(res), function(x) sum(res[[x]][["condition"]]) / nchar(lst[[x]]))
在@Sobrique的评论之后,如果除以长度意味着与条件相关的发生次数除以每个基因中的字符总数,则可以执行以下操作:
lst <- list(gene1, gene2, gene3)
res <- lapply(lst, function(x) {
data.frame(stri_locate_all_fixed(x, "GTG")) %>%
mutate(condition = start %in% seq(1, nchar(x), 3))
})
lapply(1:length(res), function(x) sum(res[[x]][["condition"]]) / nchar(lst[[x]]))
这将使:
#[[1]]
# start end condition
#1 4 6 TRUE
#
#[[2]]
# start end condition
#1 NA NA FALSE
#
#[[3]]
# start end condition
#1 3 5 FALSE
#2 9 11 FALSE
#3 21 23 FALSE
#4 70 72 TRUE
#5 75 77 FALSE
#[[1]]
#[1] 0.004830918
#
#[[2]]
#[1] 0
#
#[[3]]
#[1] 0.003021148
这是我根据您的需求创建的函数。我很确定还有比这更好的替代方法,但这解决了问题
require(stringi)
input_gene_list<- list(gene1= "GTGGGGGTTTGTGGGGGTG", gene2= "GTGGGGGTTTGTGGGGGTG", gene3= "GTGGGGGTTTGTGGGGGTG")
gene_counter<- function(gene){
x<- gene
y<- gsub(pattern = "GTG",replacement = "GTG ", x = x, perl=TRUE)
if(str_count(y,pattern = "GTG")) {
gene_count<- unlist(gregexpr(pattern = " ", y))
counter<- 0
for(i in 1:length(gene_count)){
if((gene_count[i] %% 3) == 1) counter=counter+1
}
return(counter/nchar(x))
}
}
output_list<- lapply(input_gene_list, function(x) gene_counter(x))
result<- t(as.data.frame(output_list))
也分享你的想法吧!谢谢 这里有一个Perl解决方案,可以按您的要求执行
但我不明白您的示例输出是如何导出的:第一个和最后一个序列在您需要的位置上只有一次出现GTG
,而第二个序列根本没有。这意味着输出分别为1/207
、0/74
和1/331
。这些都不是你所期望的3
和6.3
此程序希望输入文件的路径作为命令行上的参数
使用严格;
使用“全部”警告;
打印“基因频率\n”;
我的$name;
本地$/='>';
而(){
咀嚼;
下一个除非/\S/;
我的($name,$seq)=拆分/\n/,$\u2;
$seq=~tr/A-Z//cd;
我的$n=0;
而($seq=~/(?=GTG)/g){
++$n如果$-[0]%3==0;
}
printf“%-7s%.6f\n”,$name,$n/长度($seq);
}
输出
基因频率
基因1 0.004831
Gene20.000000
基因3 0.003021
您已经尝试过解决这个问题了吗?您使用perl标记是因为您在R中使用perl正则表达式,还是因为您也可以使用纯perl解决方案?我想使用perl,因为我的输入非常大,如果在第一个字符串中有一个GTG
实例,这是否意味着“频率”应该是1/207
?我的输出只是一个例子谢谢,看起来不错。字符串长度是字母数。你会怎么写?如何调用输入数据?已编辑<代码>
是perl非常方便的特性,值得学习。是否可以将频率输出作为一个单独的列。我想根据频率对输出进行排序。通常我会对-nk2进行排序,但频率并不是它看起来微不足道的第二列。编辑该打印行;工作完成了。频率为上述示例中的第4列。但是打印“$gene”,@hits/length($gene\u str),“\n”
将执行您想要的操作。拆分/(…)/
拆分为3个字符?$line=~/(…)/g
或解包(“(a3)*',$line)
比拆分/(…)/,$line
我的输入看起来有点不同,您能检查换行符对输出的影响吗?@user2300940如果中间有换行符,则此方法无效。您在接受解决方案后编辑了问题。这不是堆栈溢出应该如何工作的。你现在提出了一个完全不同的问题。我建议你问一个新问题。我不明白这里的反对票。完全可行的解决方案+1我认为,无论谁对这个答案投了反对票,请你引述一个理由,或者至少自己尝试一下解决方案。我看不出有什么理由在没有解释的情况下对它投反对票。我自己也收到了反对票,第三方也对它发表了评论。我建议你学会接受它:这只是-1点我一点也不担心消极的方面。我只是在想应该有一个很好的理由投反对票。它至少会让这个人知道他的方法有什么问题。我只是想和这里的其他伟人一起学习。投票是匿名的,要求解释是徒劳的。我相信你们国家有匿名投票支持民主政府?你有没有看到他们在每一次投票中为反对党跳舞和指责?对于一个自称阿拉丁的人来说,要求公开和诚实是很奇怪的
require(stringi)
input_gene_list<- list(gene1= "GTGGGGGTTTGTGGGGGTG", gene2= "GTGGGGGTTTGTGGGGGTG", gene3= "GTGGGGGTTTGTGGGGGTG")
gene_counter<- function(gene){
x<- gene
y<- gsub(pattern = "GTG",replacement = "GTG ", x = x, perl=TRUE)
if(str_count(y,pattern = "GTG")) {
gene_count<- unlist(gregexpr(pattern = " ", y))
counter<- 0
for(i in 1:length(gene_count)){
if((gene_count[i] %% 3) == 1) counter=counter+1
}
return(counter/nchar(x))
}
}
output_list<- lapply(input_gene_list, function(x) gene_counter(x))
result<- t(as.data.frame(output_list))
[,1]
gene1 0.1052632
gene2 0.1052632
gene3 0.1052632