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 -t
solo 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.awk
para awk -v seed="$RANDOM" -f tst.awk
obtener diferentes números aleatorios generados en cada invocación.
Respuesta2
Un script actualizado porque bc
no funcionaba bien con los signos principales de los números, por lo que se cambió awk
a domath
.
También se cambió a usar shuf
para 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