bashを用いたランダム突然変異

bashを用いたランダム突然変異

たとえば、文字列があります。

1234567890

この文字列のランダムな位置を、他の文字列セットのランダムな順序でその位置に置き換えたいと思います。

ABCDEFGHIJ
KLMNOPQRST
UVWXYZABCD
...

3回の置換を選択した場合、スクリプトは3、7、8などの3つのランダム数と1、1、3などの3つのランダムシーケンスを選択して予想される出力を生成する必要があります。

12C456GB90

明らかなループなしでこれを行う方法はありますか?私はランダムな位置とランダムな行シーケンスを生成し、1回の置換を実行し、出力でプロセスを繰り返し、繰り返し、そして繰り返す単純なbashスクリプトを書いた。これはうまく機能しますが、実際のファイル(例よりはるかに大きい)では10,000を超える代替アイテムを作成しようとしています。ああ、そして複数の「突然変異」修飾配列を生成するには、これを何度も実行する必要があります。

編集:現在、次のようなものを使用しています。

#chose random number between 1 and the number of characters in the string
randomposition=$(jot -r 1 1 $seqpositions)
#chose a random number between 1 and the number of lines in the set of potential replacement strings
randomline=$(jot -r 1 1 $alignlines)
#find the character at randomline:randomposition
newAA=$(sed -n "$randomline,$randomline p" $alignmentfile | cut -c$randomposition)
#replace the character at 'string:randomposition' with the character at 'randomline:randomposition'
sed "s/./$newAA/$randomposition" $sequencefile

(明らかに少し余分なビットがあります)何千回も繰り返します。

答え1

メモ:

これはそんなに楽しみのためのものです。の同等のプログラムはCはるかに簡単で、はるかに高速です。bash私たちはそれについて話すことはありません。

次のperlスクリプトは、私のラップトップで約10秒以内に約1Mのシーケンスリストと約10,000のソートリストを変更します。

#! /usr/bin/perl
# usage mutagen number_of_replacements alignment_file [ sequence_file ..]
use strict;
my $max = shift() - 1;
my $algf = shift;
open my $alg, $algf or die "open $algf: $!";
my @alg = <$alg>;

sub prand { map int(rand() * $_[0]), 0..$max }
while(<>){
    my @ip = prand length() - 1;
    my @op = prand scalar @alg;
    for my $i (0..$max){
        my $p = $ip[$i];
        substr $_, $p, 1, substr $alg[$op[$i]], $p, 1;
    }
    print;
}

使用例:

$ cat seq
1634870295
5684937021
2049163587
6598471230
$ cat alg
DPMBHZJEIO
INTMJZOYKQ
KNTXGLCJSR
GLJZRFVSEX
SYJVHEPNAZ
$ perl mutagen 3 alg seq
1L3V8702I5
5684HE7Y21
2049JZC587
6598H7C2E0

生成されたn乱数が異なる必要がある場合は、prand次のように変更する必要があります。

sub prand {
    my (@r, $m, %h);
    die "more replacements than positions/alignments" if $max >= $_[0];
    for(0..$max){
        my $r = int(rand() * $_[0]);
        $r = ($r + 1) % $_[0] while $h{$r};
        $h{$r} = 1;
        push @r, $r;
    }
    @r;
}

スイッチが与えられたときに色の変化をきれいに印刷するデバッグサポートバージョン-d

#! /usr/bin/perl
# usage mutagen [-d] number_of_replacements alignment_file [ sequence_file ..]
use strict;

my $debug = $ARGV[0] eq '-d' ? shift : 0;
my $max = shift() - 1;
my $algf = shift;
open my $alg, $algf or die "open $algf: $!";
my @alg = <$alg>;

sub prand { map int(rand() * $_[0]), 0..$max } 
while(<>){
    my @ip = prand length() - 1;
    my @op = prand scalar @alg;

    if($debug){
        my $t = ' ' x (length() - 1);
        substr $t, $ip[$_], 1, $ip[$_] for 0..$max;
        warn "@ip | @op\n    $_    $t\n";
        for my $i (0..$max){
            my $t = $alg[$op[$i]];
            $t =~ s/(.{$ip[$i]})(.)/$1\e[1;31m$2\e[m/;
            printf STDERR " %2d %s", $op[$i], $t;
        }
    }
    for my $i (0..$max){
        my $p = $ip[$i];
        substr $_, $p, 1, substr $alg[$op[$i]], $p, 1;
    }
    print;
    if($debug){
        my @t = split "", $_;
        for my $i (0..$max){
            $_ = "\e[1;31m$_\e[m" for $t[$ip[$i]];
        }
        warn "  = ", @t, "\n";
    }
}

答え2

この線形性は無限の数のランダムキーを生成します。

cat /dev/urandom | tr -dc 'A-Z0-9' | fold -w 10 | head -n 1

出力例:

MB0JZZ85VI
2OKOY4JL61
2YN7B71Z6K
KH29TYCQ4K
B4N1XOFY5O

説明する:

/dev/random/dev/urandomまたは/dev/arandomシステムで疑似乱数ジェネレータとして機能する特別なファイルである可能性があります。これにより、デバイスドライバや他のソースから収集された周囲のノイズにアクセスでき、より多くの情報を得ることができます。ここ

これ折りたたみコマンドUNIX で指定されたファイルや標準入力の内容を折りたたむためのコマンドラインユーティリティです。デフォルトでは、最大幅は80列に折り返されます。また、列幅の指定とバイト単位の改行もサポートしています。wコマンドのフラグは列のfold幅を表し、これはランダムに生成されたキーに含まれるバイト数を調整するのに間接的に役立ちます。

コマンドの正規表現は、tr任意のキーに含まれる文字を制御します。

head -n生成される任意のキー数を調整します。たとえば、-n 1に置き換えると10000、10,000個のキーが生成されます。

答え3

bash実行中の外部プロセスの数が多く、初期試行が遅くなります。すべての乱数に対して呼び出され、jotすべての文字列操作はtwosedとoneを使用しますcut

bash純粋な代わりに使用すると、sh次の利点が得られます。$ランダム変える,部分文字列拡張そしてソート。これにより、外部コマンド(またはサブシェル)なしで交換を実行できますbash

#!/bin/bash

count=$1
read sequence < $2
IFS=$'\n' read -d '' -a replacements < $3
len=${#sequence}
choices=${#replacements[*]}

while ((count--)) ; do
        pos=$(($RANDOM % $len))
        choice=$(($RANDOM % $choices))
        replacement=${replacements[$choice]}
        sequence=${sequence:0:$pos}${replacement:$pos:1}${sequence:$((pos+1))}
done

echo "$sequence"

$RANDOM は 32767 を超えないので、シーケンスがそれより大きいか、そのサイズに近い場合は$RANDOM % maximum

コンパイルされた言語はもちろん、専用のスクリプト言語をスピードの点で上回ることはまだ不可能です。

関連情報