Случайно выбрать регион и обработать его, несколько раз - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть такие данные

>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

, затем случайным образом получаю одну область с10 букв, которые я пытался использовать shuf безуспешно,

shuf -n1000 data.txt 

, затем я пытался использовать awk и не смог либо

awk 'BEGIN {srand()} !/^$/ { if (rand() == 10) print $0}'

, затем вычислил число F и сохранилэто в файле

grep -i -e [F] |wc -l 

Обратите внимание, мы не должны брать один и тот же регион дважды

Ответы [ 4 ]

0 голосов
/ 13 февраля 2019

Так как ваш входной файл огромен, я бы сделал это следующим образом:

  1. выберите случайные 10-символьные строки из каждой строки вашего входного файла
  2. перемешайте их, чтобы получитьколичество выборок, которое вы хотите в случайном порядке
  3. считать Fs

например

$ 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 (то есть в 10 раз больше строк ввода, чем в OP, максимальная длина файла составляла 10000000, чтобы учесть, что часть awk генерирует N строк вывода на 1 строку ввода и в 10 раз больше строк вывода, чем требуется OPопубликовал 1000), и он работал нормально, и на его завершение ушло всего несколько секунд.

0 голосов
/ 13 февраля 2019

Вот одно решение, использующее 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

$
0 голосов
/ 13 февраля 2019

Я должен предположить кое-что здесь и оставить некоторые ограничения

  • Выбор случайных областей не зависит от линий;они просто выбраны из текста

  • Порядок не имеет значения;в файле должно быть только 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 loop), возможно , что эта строка короче, чем остальные необходимые символы ($chars_left).Это очень маловероятно и нуждается в дополнительной проверке, которая здесь не указана.

  • Случайные числа обрезаются на дубли.Это искажает последовательность, но в мельчайших подробностях то, что здесь не имеет значения;и мы можем остаться с меньшим количеством номеров, чем запрошено, но только очень маленьким

Обработка вопросов, касающихся случайности

«Случайность» здесьдовольно простой, что кажется подходящим.Нам также необходимо учесть следующее:

Случайные числа рисуются в интервале, охватывающем размер файла, int(rand -s $file) (минус размер региона).Но линии >sp пропускаются, и любые из наших чисел, которые могут попадать в эти строки, не будут использоваться, и поэтому у нас может оказаться меньше регионов, чем нарисованных чисел.Эти строки короче, следовательно, с меньшей вероятностью иметь числа на них, и поэтому не многие числа теряются, но в некоторых прогонах я пропускал даже 3 из 10 пропущенных чисел, в результате чего случайная выборка имела размер 70% желаемого размера.

Если это беспокоит, есть способы подойти к нему.Чтобы не искажать дистрибутив еще дальше, все они должны включать предварительную обработку файла.

Приведенный выше код выполняет начальный прогон файла, чтобы вычислить долю символов, которые будут пропущены.Это затем используется для увеличения числа случайных точек.Это, конечно, «средняя» мера, но она все равно должна давать количество областей, близких к желаемым, для достаточно больших файлов.

Необходимы более подробные измерения, чтобы увидеть, какие случайные точки (гораздо большего) распределения будут потеряны для пропущенных линий, а затем повторно выбрать, чтобы учесть это.Это может все еще мешать распространению, что, возможно, не является проблемой здесь, но более конкретно, может просто не понадобиться.

Во всем этом вы читаете большой файл дважды.Дополнительное время обработки должно быть только в секундах, но если это недопустимо, измените функцию 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;
}

Пожалуйста, подробнее о проверке ошибок.Смотрите, например, этот пост и ссылки на детали.

Простейшее использование: driver_random.pl -n 4, но вы можете указать все основные параметры программы.

Примечание: Вызываемая программа (random_regions.pl выше) должна быть исполняемой.


Некоторые, от простых до более способных: IPC :: System :: Simple, Capture :: Tiny , IPC :: Run3 .(Затем прибывает IPC::Run, используемый здесь.) Также смотрите String :: ShellQuote , чтобы подготовить команды без проблем с кавычками, ошибок внедрения оболочки и других проблем.Смотрите ссылки (примеры), собранные в этом посте , например.

0 голосов
/ 13 февраля 2019

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
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...