Como alterar aleatoriamente a ordem de duas colunas simultaneamente 1000 vezes usando valores de simulação?

Como alterar aleatoriamente a ordem de duas colunas simultaneamente 1000 vezes usando valores de simulação?

Eu tenho um dado parecido com este:

    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    

Devo criar 2 colunas nomeadas como "simulação1" e "simulação2" com números aleatórios dentro delas, como abaixo:

 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

depois disso, classifico as colunas "ID" e "pheno" de acordo com o valor na coluna "simulação1", então calculo a média de "pheno" para as 40% principais linhas que serão 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 

Em seguida, classifico as colunas "ID" e "feno" de acordo com o valor na coluna "simulação2" e, em seguida, calculo a média de "feno" para as 40% principais linhas, que será 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

Então, a diferença entre as médias dos 40% principais usando classificações diferentes seria -0,093 = 0,1 - 0,193.

Para a segunda rodada, as duas primeiras colunas (ID e feno) permanecerão constantes, mas devo criar novos valores nas colunas "simulação1" e "simulação2". Eu crio valores em "simulação1" e "simulação2" no Excel usando a função RAND()*. Mas é impossível repetir 1000 vezes. Estou me perguntando como posso criar um loop no Linux para o que desejo.

O resultado final será:

row_name top40%average_simulate1  top40%average_simulate2  difference 

   1          0.193                    0.1                    -0.093
   2          
   .
   .
   .
   1000   

Responder1

Em todos os casos, o abaixo | column -té apenas adicionado para deixar a saída visualmente alinhada.

1) Devo criar 2 colunas nomeadas como "simulação1" e "simulação2" com números aleatórios dentro delas

$ 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) depois classifico as colunas "ID" e "pheno" de acordo com o valor da coluna "simulação1"

$ 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) então calculo a média de "feno" para as primeiras 40% das linhas

$ 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

Espero que você consiga descobrir o resto. Acima, dei ao awk a mesma semente em cada chamada para que a saída permanecesse constante para facilitar o rastreamento através dos estágios de cálculo. Altere as chamadas para tst.awkpara awk -v seed="$RANDOM" -f tst.awkobter diferentes números aleatórios gerados em cada chamada.

Responder2

Um script atualizado porque bcnão funcionava bem com os sinais iniciais dos números, então mudou para awkno arquivo domath.

Também mudou para usar shufpara embaralhar os índices do array para cada iteração, pois é mais simples com um array fixo.

#!/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

informação relacionada