如何使用模擬值同時隨機改變兩列的順序 1000 次?

如何使用模擬值同時隨機改變兩列的順序 1000 次?

我有一個數據看起來像這樣:

    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    

我應該創建 2 個名為“simulation1”和“simulation2”的列,其中包含隨機數,如下所示:

 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

之後,我根據「simulation1」列上的值對「ID」和「pheno」列進行排序,然後計算前 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 

然後,我根據「simulation2」列上的值對「ID」和「pheno」列進行排序,然後計算前 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。

對於第二輪,前兩列(ID 和 pheno)將保持不變,但我應該在「simulation1」和「simulation2」欄中建立新值。我使用函數 RAND()* 在 Excel 中的“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”,其中包含隨機數

$ 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)之後,我根據「simulation1」列上的值對「ID」和「pheno」列進行排序

$ 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% 行的「pheno」平均值

$ 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 提供了相同的種子,以便輸出保持不變,以便於追蹤整個計算階段。變更對 to 的調用,tst.awk以便awk -v seed="$RANDOM" -f tst.awk在每次調用時產生不同的隨機數。

答案2

更新的腳本因為bc與數字上的前導符號不能很好地配合,所以更改awkdomath.

也更改為使用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

相關內容