我有这样的数据
>sp|Q96A73|P33MX_HUMAN Putative monooxygenase p33MONOX OS=Homo sapiens OX=9606 GN=KIAA1191 PE=1 SV=1
RNDDDDTSVCLGTRQCSWFAGCTNRTWNSSAVPLIGLPNTQDYKWVDRNSGLTWSGNDTCLYSCQNQTKGLLYQLFRNLFCSYGLTEAHGKWRCADASITNDKGHDGHRTPTWWLTGSNLTLSVNNSGLFFLCGNGVYKGFPPKWSGRCGLGYLVPSLTRYLTLNASQITNLRSFIHKVTPHR
>sp|P13674|P4HA1_HUMAN Prolyl 4-hydroxylase subunit alpha-1 OS=Homo sapiens OX=9606 GN=P4HA1 PE=1 SV=2
VECCPNCRGTGMQIRIHQIGPGMVQQIQSVCMECQGHGERISPKDRCKSCNGRKIVREKKILEVHIDKGMKDGQKITFHGEGDQEPGLEPGDIIIVLDQKDHAVFTRRGEDLFMCMDIQLVEALCGFQKPISTLDNRTIVITSHPGQIVKHGDIKCVLNEGMPIYRRPYEKGRLIIEFKVNFPENGFLSPDKLSLLEKLLPERKEVEE
>sp|Q7Z4N8|P4HA3_HUMAN Prolyl 4-hydroxylase subunit alpha-3 OS=Homo sapiens OX=9606 GN=P4HA3 PE=1 SV=1
MTEQMTLRGTLKGHNGWVTQIATTPQFPDMILSASRDKTIIMWKLTRDETNYGIPQRALRGHSHFVSDVVISSDGQFALSGSWDGTLRLWDLTTGTTTRRFVGHTKDVLSVAFSSDNRQIVSGSRDKTIKLWNTLGVCKYTVQDESHSEWVSCVRFSPNSSNPIIVSCGWDKLVKVWNLANCKLK
>sp|P04637|P53_HUMAN Cellular tumor antigen p53 OS=Homo sapiens OX=9606 GN=TP53 PE=1 SV=4
IQVVSRCRLRHTEVLPAEEENDSLGADGTHGAGAMESAAGVLIKLFCVHTKALQDVQIRFQPQL
>sp|P10144|GRAB_HUMAN Granzyme B OS=Homo sapiens OX=9606 GN=GZMB PE=1 SV=2
MQPILLLLAFLLLPRADAGEIIGGHEAKPHSRPYMAYLMIWDQKSLKRCGGFLIRDDFVLTAAHCWGSSINVTLGAHNIKEQEPTQQFIPVKRPIPHPAYNPKNFSNDIMLLQLERKAKRTRAVQPLRLPSNKAQVKPGQTCSVAGWGQTAPLGKHSHTLQEVKMTVQEDRKCES
>sp|Q9UHX1|PUF60_HUMAN Poly(U)-binding-splicing factor PUF60 OS=Homo sapiens OX=9606 GN=PUF60 PE=1 SV=1
MGKDYYQTLGLARGASDEEIKRAYRRQALRYHPDKNKEPGAEEKFKEIAEAYDVLSDPRKREIFDRYGEEGLKGSGPSGGSGGGANGTSFSYTFHGDPHAMFAEFFGGRNPFDTFFGQRNGEEGMDIDDPFSGFPMGMGGFTNVNFGRSRSAQEPARKKQDPPVTHDLRVSLEEIYSGCTKKMKISHK
>sp|Q06416|P5F1B_HUMAN Putative POU domain, class 5, transcription factor 1B OS=Homo sapiens OX=9606 GN=POU5F1B PE=5 SV=2
IVVKGHSTCLSEGALSPDGTVLATASHDGYVKFWQIYIEGQDEPRCLHEWKPHDGRPLSCLLFCDNHKKQDPDVPFWRFLITGADQNRELKMWCTVSWTCLQTIRFSPDIFSSVSVPPSLKVCLDLSAEYLILSDVQRKVLYVMELLQNQEEGHACFSSISEFLLTHPVLSFGIQVVSRCRLRHTEVLPAEEENDSLGADGTHGAGAMESAAGVLIKLFCVHTKALQDVQIRFQPQLNPDVVAPLPTHTAHEDFTFGESRPELGSEGLGSAAHGSQPDLRRIVELPAPADFLSLSSETKPKLMTPDAFMTPSASLQQITASPSSSSSGSSSSSSSSSSSLTAVSAMSSTSAVDPSLTRPPEELTLSPKLQLDGSLTMSSSGSLQASPRGLLPGLLPAPADKLTPKGPGQVPTATSALSLELQEVEP
>sp|O14683|P5I11_HUMAN Tumor protein p53-inducible protein 11 OS=Homo sapiens OX=9606 GN=TP53I11 PE=1 SV=2
MIHNYMEHLERTKLHQLSGSDQLESTAHSRIRKERPISLGIFPLPAGDGLLTPDAQKGGETPGSEQWKFQELSQPRSHTSLKVSNSPEPQKAVEQEDELSDVSQGGSKATTPASTANSDVATIPTDTPLKEENEGFVKVTDAPNKSEISKHIEVQVAQETRNVSTGSAENEEKSEVQAIIESTPELDMDKDLSGYKGSSTPTKGIENKAFDRNTESLFEELSSAGSGLIGDVDEGADLLGMGREVENLILENTQLLETKNALNIVKNDLIAKVDELTCEKDVLQGELEAVKQAKLKLEEKNRELEEELRKARAEAEDARQKAKDDDDSDIPTAQRKRFTRVEMARVLMERNQYKERLMELQEAVRWTEMIRASRENPAMQEKKRSSIWQFFSRLFSSSSNTTKKPEPPVNLKYNAPTSHVTPSVK
我想从中随机挑选一个包含10个字母的区域,然后计算F的数量,我想这样做一定次数,例如1000次甚至更多次
例如,我随机选择
LVPSLTRYLT 0
然后
ITNLRSFIHK 1
然后再次随机去接连续10个字母
AHSRIRKERP 0
此过程一直持续到达到要求的运行次数为止。我想将所有随机选择的值与它们的值一起存储,因为那样我想计算出看到F的次数
所以我要执行以下操作
# first I remove the header
grep -v ">" data.txt > out.txt
然后随机获得一个我尝试使用shuf
并没有成功的10个字母的区域,
shuf -n1000 data.txt
然后我尝试使用awk,但也不成功
awk 'BEGIN {srand()} !/^$/ { if (rand() == 10) print $0}'
然后计算F的数量并将其保存在文件中
grep -i -e [F] |wc -l
请注意,我们不应该在相同的地区接两次
答案 0 :(得分:4)
我必须在这里承担一些事情,并保留一些限制
要选择的随机区域不依赖于行;他们只是从文本中挑选出来的
顺序无关紧要;文件中应该只有N个区域分布
文件的大小可能达到千兆字节,因此无法先完整读取(会容易得多!)
有未处理(边缘或不太可能)的情况,在代码后进行了讨论
首先建立一个随机数排序列表;这些是文件中区域开始的位置。然后,在读取每一行时,计算其在文件中的字符范围,并检查我们的数字是否在其中。如果有的话,它们会标记每个随机区域的开头:从这些字符开始,选择所需长度的子字符串。检查子字符串是否适合该行。
use warnings;
use strict;
use feature 'say';
use Getopt::Long;
use List::MoreUtils qw(uniq);
my ($region_len, $num_regions) = (10, 10);
my $count_freq_for = 'F';
#srand(10);
GetOptions(
'num-regions|n=i' => \$num_regions,
'region-len|l=i' => \$region_len,
'char|c=s' => \$count_freq_for,
) or usage();
my $file = shift || usage();
# List of (up to) $num_regions random numbers, spanning the file size
# However, we skip all '>sp' lines so take more numbers (estimate)
open my $fh, '<', $file or die "Can't open $file: $!";
$num_regions += int $num_regions * fraction_skipped($fh);
my @rand = uniq sort { $a <=> $b }
map { int(rand (-s $file)-$region_len) } 1..$num_regions;
say "Starting positions for regions: @rand";
my ($nchars_prev, $nchars, $chars_left) = (0, 0, 0);
my $region;
while (my $line = <$fh>) {
chomp $line;
# Total number of characters so far, up to this line and with this line
$nchars_prev = $nchars;
$nchars += length $line;
next if $line =~ /^\s*>sp/;
# Complete the region if there wasn't enough chars on the previous line
if ($chars_left > 0) {
$region .= substr $line, 0, $chars_left;
my $cnt = () = $region =~ /$count_freq_for/g;
say "$region $cnt";
$chars_left = -1;
};
# Random positions that happen to be on this line
my @pos = grep { $_ > $nchars_prev and $_ < $nchars } @rand;
# say "\tPositions on ($nchars_prev -- $nchars) line: @pos" if @pos;
for (@pos) {
my $pos_in_line = $_ - $nchars_prev;
$region = substr $line, $pos_in_line, $region_len;
# Don't print if there aren't enough chars left on this line
last if ( $chars_left =
($region_len - (length($line) - $pos_in_line)) ) > 0;
my $cnt = () = $region =~ /$count_freq_for/g;
say "$region $cnt";
}
}
sub fraction_skipped {
my ($fh) = @_;
my ($skip_len, $data_len);
my $curr_pos = tell $fh;
seek $fh, 0, 0 if $curr_pos != 0;
while (<$fh>) {
chomp;
if (/^\s*>sp/) { $skip_len += length }
else { $data_len += length }
}
seek $fh, $curr_pos, 0; # leave it as we found it
return $skip_len / ($skip_len+$data_len);
}
sub usage {
say STDERR "Usage: $0 [options] file", "\n\toptions: ...";
exit;
}
取消注释srand
行,以便始终进行相同的运行以进行测试。
请注意。
一些极端情况
如果10个长窗口从其随机位置开始不适合该行,则在下一行中完成-但是此行上的(任意)更多个随机位置被排除在外。因此,如果我们的随机列表有1120和1122,而一条线在1125结束,则跳过从1122开始的窗口。不太可能,没有任何后果(除了减少一个区域)。
当下一行(if
循环中的第一个while
)填充不完整区域时,可能剩余的所需字符($chars_left
)。这是极不可能的,需要在那里进行额外的检查。
随机数被删除。这使顺序变得歪斜,但是在此刻不重要的是什么。而且我们可能留下的数量少于要求的数量,但是数量很少
处理有关随机性的问题
这里的“随机性”是非常基本的,似乎很合适。我们还需要考虑以下内容。
在跨越文件大小int(rand -s $file)
(减去区域大小)的间隔内绘制随机数。但是,>sp
行被跳过,并且可能落入这些行中的任何数字都不会被使用,因此,最终我们得到的区域可能少于绘制的数字。这些行较短,因此在其上出现数字的机会较小,因此丢失了很多数字,但是在某些运行中,我看到甚至跳过了十分之三的数字,最终得到了所需样本大小的70%。 / p>
如果这很麻烦,则有多种方法可以解决。为了不进一步分散发行版,它们都应涉及预处理文件。
上面的代码对文件进行了初始运行,以计算将被跳过的字符比例。然后将其用于增加绘制的随机点的数量。这当然是“平均”的措施,但仍应产生接近足够大文件所需区域的数量。
更详细的度量将需要查看(更大)分布的哪些随机点将丢失到跳过的行中,然后重新采样以解决这一问题。这可能仍然会影响发行版,在这里可以说不是问题,但更重要的是根本不需要。
在所有这些中,您两次读取了大文件。额外的处理时间应仅以秒为单位,但是如果不可接受,则将功能fraction_skipped
更改为仅读取文件的10-20%。对于大文件,这仍应提供合理的估计。
有关特定测试用例的说明
使用srand(10)
(靠近开头的注释行),我们得到了随机数,这样,在一行上,该区域在行尾之前开始了8个字符!因此,这种情况确实会测试代码以完成下一行的区域。
一个简单的驱动程序可以运行上述给定次数,以进行统计。
仅使用内置工具(system
,qx
)来进行操作既麻烦又挑剔;实际上,一个需要模块。所以我在这里使用IPC::Run。还有很多其他选项。†
根据统计信息调整并添加代码以进行处理;输出在文件中。
use warnings;
use strict;
use feature 'say';
use Getopt::Long;
use IPC::Run qw(run);
my $outdir = 'rr_output'; # pick a directory name
mkdir $outdir if not -d $outdir;
my $prog = 'random_regions.pl'; # your name for the program
my $input = 'data_file.txt'; # your name for input file
my $ch = 'F';
my ($runs, $regions, $len) = (10, 10, 10);
GetOptions(
'runs|n=i' => \$runs,
'regions=i' => \$regions,
'length=i' => \$len,
'char=s' => \$ch,
'input=s' => \$input
) or usage();
my @cmd = ( $prog, $input,
'--num-regions', $regions,
'--region-len', $len,
'--char', $ch
);
say "Run: @cmd, $runs times.";
for my $n (1..$runs) {
my $outfile = "$outdir/regions_r$n.txt";
say "Run #$n, output in: $outdir/$outfile";
run \@cmd, '>', $outfile or die "Error with @cmd: $!";
}
sub usage {
say STDERR "Usage: $0 [options]", "\n\toptions: ...";
exit;
}
请展开错误检查。例如,请参见this post和详细信息的链接。
最简单的用法:driver_random.pl -n 4
,但是您可以提供所有主程序的参数。
注意:所调用的程序(上面的random_regions.pl
必须是可执行的。
†从简单到功能更强大的一些软件:IPC::System::Simple,Capture::Tiny,IPC::Run3。 (然后在这里使用IPC::Run
。)另请参见String::ShellQuote,以准备命令而不引用问题,shell注入错误和其他问题。例如,请参阅以this post汇编的链接(示例)。
答案 1 :(得分:1)
awk
来营救!
您没有指定,但是有两个随机动作在进行。我独立对待他们,可能并非如此。首先选择一行,然后从该行中随机选择一个10个字母的子字符串。
这假设文件(或文件的一半)可以容纳在内存中。否则,将文件分成相等的块,然后逐个运行。这样做会减少一些群集,但不确定这种情况下的重要性。 (如果您有一个大文件,则可能所有样本都可以从前半部分中抽取出来,通过拆分可以消除这种可能性)。在某些情况下,这是理想的属性。不知道你的情况。
$ awk 'BEGIN {srand()}
!/^>/ {a[++n]=$0}
END {while(i++<1000)
{line=a[int(rand()*n)+1];
s=int(rand()*(length(line)-9));
print ss=substr(line,s,10), gsub(/F/,"",ss)}}' file
GERISPKDRC 0
QDEPRCLHEW 0
LLYQLFRNLF 2
GTHGAGAMES 0
TKALQDVQIR 0
FCVHTKALQD 1
SNKAQVKPGQ 0
CMECQGHGER 0
TRRFVGHTKD 1
...
答案 2 :(得分:0)
这是使用Perl的一种解决方案
它将整个文件插入内存。然后,以>开头的行将被删除。
在这里,我循环10次$i<10
,您可以在此处增加计数。
然后,通过传递文件的长度并使用rand值来调用rand函数,计算substr为10。 $s!~/\n/
的警惕是确保我们不要选择跨换行符的子字符串。
$ perl -0777 -ne '$_=~s/^>.+?\n//smg; while($i<10) { $x=rand(length($_)); $s=substr($_,$x,10); $f=()=$s=~/F/g; if($s!~/\n/) { print "$s $f\n" ;$i++} else { $i-- } } '
random10.txt
ENTQLLETKN 0
LSEGALSPDG 0
LRKARAEAED 0
RLWDLTTGTT 0
KWSGRCGLGY 0
TRRFVGHTKD 1
PVKRPIPHPA 0
GMVQQIQSVC 0
LTHPVLSFGI 1
KVNFPENGFL 2
$
要知道生成的随机数
$ perl -0777 -ne '$_=~s/^>.+?\n//smg; while($i<10) { $x=rand(length($_)); $s=substr($_,$x,10); $f=()=$s=~/F/g; if($s!~/\n/) { print "$s $f $x\n" ;$i++} else { $i-- } }
' random10.txt
QLDGSLTMSS 0 1378.61409368207
DLIAKVDELT 0 1703.46689004765
SGGGANGTSF 1 900.269562152326
PEELTLSPKL 0 1368.55540468164
TCLSEGALSP 0 1016.50744004085
NRTWNSSAVP 0 23.7868578293154
VNFPENGFLS 2 363.527933104776
NSGLTWSGND 0 48.656607650744
MILSASRDKT 0 422.67705815168
RRGEDLFMCM 1 290.828530365
AGDGLLTPDA 0 1481.78080339531
$
答案 3 :(得分:0)
由于您的输入文件很大,因此请按以下步骤操作:
例如
$ cat tst.sh
#!/bin/env bash
infile="$1"
sampleSize=10
numSamples=15
awk -v sampleSize="$sampleSize" '
BEGIN { srand() }
!/^>/ {
begPos = int((rand() * sampleSize) + 1)
endPos = length($0) - sampleSize
for (i=begPos; i<=endPos; i+=sampleSize) {
print substr($0,i,sampleSize)
}
}
' "$infile" |
shuf -n "$numSamples"
。
$ ./tst.sh file
HGDIKCVLNE
QDEPRCLHEW
SEVQAIIEST
THDLRVSLEE
SEWVSCVRFS
LTRYLTLNAS
KDGQKITFHG
SNSPEPQKAV
QGGSKATTPA
QLLETKNALN
LLFCDNHKKQ
DETNYGIPQR
IRFQPQLNPD
LQTIRFSPDI
SLKRCGGFLI
$ ./tst.sh file | awk '{print $0, gsub(/F/,"")}'
SPKLQLDGSL 0
IKLFCVHTKA 1
VVSRCRLRHT 0
SPEPQKAVEQ 0
AYNPKNFSND 1
FGESRPELGS 1
AGDGLLTPDA 0
VGHTKDVLSV 0
VTHDLRVSLE 0
PISLGIFPLP 1
ASQITNLRSF 1
LTRPPEELTL 0
FDRYGEEGLK 1
IYIEGQDEPR 0
WNTLGVCKYT 0
在对实际数据运行时,只需将numSamples从15更改为1000即可。
以上内容取决于shuf -n
能够处理我们向其投入的任何输入,大概就像sort
通过使用分页所做的那样。如果在这方面失败了,那么显然您必须为该部分选择/实施其他工具。 FWIW我尝试过seq 100000000 | shuf -n 10000
(即,输入的行数是OP发布的最大文件长度10000000的10倍,以说明awk部分每1行输入产生N行输出,而输出的行数是OPs的10倍操作人员发布了1000条),并且运行正常,仅花费了几秒钟的时间。