¿Cómo cambiar aleatoriamente el orden de dos columnas simultáneamente 1000 veces usando valores de simulación?

¿Cómo cambiar aleatoriamente el orden de dos columnas simultáneamente 1000 veces usando valores de simulación?

Tengo unos datos parecidos a estos:

    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    

Debería crear 2 columnas denominadas "simulación1" y "simulación2" con números aleatorios dentro de ellas, como se muestra a continuación:

 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

después de eso ordeno las columnas "ID" y "feno" según el valor de la columna "simulación1", luego calculo el promedio de "feno" para el 40% de las filas superiores, que será 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 

Luego ordeno las columnas "ID" y "feno" según el valor de la columna "simulación2", luego calculo el promedio de "feno" para el 40% de las filas superiores, 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

Entonces, la diferencia entre los promedios del 40% superior usando diferentes clasificaciones sería -0,093 = 0,1 - 0,193.

Para la segunda ronda, las dos primeras columnas (ID y feno) permanecerán constantes, pero debo crear nuevos valores en las columnas "simulación1" y "simulación2". Creo valores en "simulación1" y "simulación2" en Excel usando la función RAND()*. Pero me es imposible repetirlo 1000 veces. Me pregunto cómo puedo crear un bucle en Linux para lo que quiero.

El resultado final será:

row_name top40%average_simulate1  top40%average_simulate2  difference 

   1          0.193                    0.1                    -0.093
   2          
   .
   .
   .
   1000   

Respuesta1

En todos los casos, a continuación | column -tsolo se agrega para alinear visualmente la salida.

1) Debería crear 2 columnas denominadas "simulación1" y "simulación2" con números aleatorios dentro de ellas.

$ 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) después de eso ordeno las columnas "ID" y "feno" según el valor de la columna "simulación1"

$ 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) luego calculo el promedio de "feno" para el 40% de las filas superiores

$ 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 puedas descubrir el resto. En lo anterior le di a awk la misma semilla en cada llamada para que la salida permaneciera constante para facilitar el seguimiento a través de las etapas de cálculo. Cambie las llamadas a tst.awkpara awk -v seed="$RANDOM" -f tst.awkobtener diferentes números aleatorios generados en cada invocación.

Respuesta2

Un script actualizado porque bcno funcionaba bien con los signos principales de los números, por lo que se cambió awka domath.

También se cambió a usar shufpara mezclar los índices de la matriz para cada iteración, ya que es más simple con una matriz fija.

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

información relacionada