次のようなデータがあります:
ID pheno
231 0.12
432 0.32
11 0.0003
134 0.33
2334 0.553
12 0.33
100 0.331
1008 1.6
223 -0.81
998 -3.001
以下のように、ランダムな数字を含む「simulation1」と「simulation2」という名前の 2 つの列を作成する必要があります。
ID pheno simulation1 simulation2
134 0.33 4.11 0.004
2334 0.553 83 0.44
12 0.33 87 0.55
100 0.331 88 12
231 0.12 0.1 2
432 0.32 3 30
11 0.0003 3.5 11
1008 1.6 89 23
223 -0.81 113 0.001
998 -3.001 220 982
その後、列「ID」と「pheno」を列「simulation1」の値に従って並べ替え、上位40%の行の「pheno」の平均を計算します。これは0.193 = (0.12+0.32+0.0003+0.33)/4になります。
ID pheno simulation1 simulation2
231 0.12 0.1 2
432 0.32 3 30
11 0.0003 3.5 11
134 0.33 4.11 0.004
2334 0.553 83 0.44
12 0.33 87 0.55
100 0.331 88 12
1008 1.6 89 23
223 -0.81 113 0.001
998 -3.001 220 982
次に、列「ID」と「pheno」を列「simulation2」の値に従って並べ替え、上位40%の行の「pheno」の平均を計算します。これは0.1 = (-0.81+0.33+0.553+0.33)/4になります。
ID pheno simulation1 simulation2
223 -0.81 113 0.001
134 0.33 4.11 0.004
2334 0.553 83 0.44
12 0.33 87 0.55
231 0.12 0.1 2
11 0.0003 3.5 11
100 0.331 88 12
1008 1.6 89 23
432 0.32 3 30
998 -3.001 220 980
そうすると、異なる並べ替えを使用した上位 40% の平均の差は -0.093 = 0.1 - 0.193 になります。
2 回目のラウンドでは、最初の 2 つの列 (ID と pheno) は一定のままですが、列 "simulation1" と "simulation2" に新しい値を作成する必要があります。Excel で関数 RAND()* を使用して "simulation1" と "simulation2" に値を作成します。ただし、これを 1000 回繰り返すことは不可能です。Linux で必要なループを作成する方法を知りたいです。
最終的な出力は次のようになります。
row_name top40%average_simulate1 top40%average_simulate2 difference
1 0.193 0.1 -0.093
2
.
.
.
1000
答え1
いずれの場合も、以下は| column -t
出力を視覚的に揃えるために追加されるだけです。
1) 「simulation1」と「simulation2」という名前の2つの列を作成し、その中にランダムな数字を入れる必要があります。
$ cat tst.awk
BEGIN { srand(seed) }
{ print $0, r(), r() }
function r() { return rand() * 100001 / 1000 }
$ awk -f tst.awk file | column -t
231 0.12 85.5574 23.7444
432 0.32 23.558 65.5853
11 0.0003 59.2486 50.3799
134 0.33 27.8248 45.7872
2334 0.553 45.7947 13.1887
12 0.33 51.6042 99.55
100 0.331 88.0281 17.4515
1008 1.6 1.37974 65.5945
223 -0.81 14.6773 97.6476
998 -3.001 87.888 31.97
2) その後、「ID」列と「pheno」列を「simulation1」列の値に従って並べ替えます。
$ awk -f tst.awk file | sort -k3,3n | column -t
1008 1.6 1.37974 65.5945
223 -0.81 14.6773 97.6476
432 0.32 23.558 65.5853
134 0.33 27.8248 45.7872
2334 0.553 45.7947 13.1887
12 0.33 51.6042 99.55
11 0.0003 59.2486 50.3799
231 0.12 85.5574 23.7444
998 -3.001 87.888 31.97
100 0.331 88.0281 17.4515
3) 次に、上位40%の行の「表現型」の平均を計算します。
$ cat tst2.awk
{ vals[NR] = $2 }
END {
max = NR * 40 / 100
for (i=1; i<=max; i++) {
sum += vals[i]
}
print sum / max
}
$ awk -f tst.awk file | sort -k3,3n | awk -f tst2.awk
0.36
残りはおわかりいただけると思います。上記では、計算の各段階を追跡しやすくするために、出力が一定になるように、awk にすべての呼び出しで同じシードを与えました。呼び出しごとに異なる乱数を生成するには、 のtst.awk
呼び出しを に変更します。awk -v seed="$RANDOM" -f tst.awk
答え2
更新されたスクリプトは、bc
数字の先頭の記号とうまく連携しなかったため、 で に変更されましawk
たdomath
。
また、shuf
固定配列の方が簡単なので、各反復で配列インデックスをシャッフルするために を使用するように変更しました。
#!/bin/bash
function domath {
#do the math using the 4 indices into the pheno array
awk '{print ($1+$2+$3+$4)/4}' <<<"${ph[$1]} ${ph[$2]} ${ph[$3]} ${ph[$4]}"
}
function iterate {
#randomise the indices and get the first 4
shuf -e 0 1 2 3 4 5 6 7 8 9 | head -n 4
}
#number of iterations
nits=100
#read the pheno values into an array
ph=($(tail -n +3 data | awk '{print $2}'))
echo -e row'\t'sim1'\t'sim2'\t'diff
for (( row=1; row<=$nits; row++ )); do
#calculate simulation1
first=$(printf "%+.3f" $(domath $(iterate)))
#calculate simulation 2
second=$(printf "%+.3f" $(domath $(iterate)))
#calculate the difference
diff=$(printf "%+.3f" $(awk '{print $2-$1}' <<<"$first $second"))
#and print
echo -e $row'\t'$first'\t'$second'\t'$diff
done