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.awk
para awk -v seed="$RANDOM" -f tst.awk
obter diferentes números aleatórios gerados em cada chamada.
Responder2
Um script atualizado porque bc
não funcionava bem com os sinais iniciais dos números, então mudou para awk
no arquivo domath
.
Também mudou para usar shuf
para 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