У меня данные выглядят так:
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
После этого я сортирую столбцы «ID» и «pheno» по значению в столбце «simulation1», затем вычисляю среднее значение «pheno» для верхних 40% строк, которое будет равно 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
Затем я сортирую столбцы «ID» и «pheno» по значению в столбце «simulation2», затем вычисляю среднее значение «pheno» для верхних 40% строк, которое будет равно 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". Я создаю значения в "simulation1" и "simulation2" в Excel с помощью функции RAND()*. Но я не могу повторить это 1000 раз. Мне интересно, как мне создать цикл в Linux для того, что мне нужно.
Окончательный результат будет следующим:
row_name top40%average_simulate1 top40%average_simulate2 difference
1 0.193 0.1 -0.093
2
.
.
.
1000
решение1
Во всех случаях ниже | column -t
просто добавляется для визуального выравнивания вывода.
1) Мне нужно создать 2 столбца с именами «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) после этого я сортирую столбцы "ID" и "pheno" по значению в столбце "simulation1"
$ 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) затем я вычисляю среднее значение "pheno" для верхних 40% строк
$ 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 одно и то же начальное значение при каждом вызове, чтобы вывод оставался постоянным для простоты отслеживания этапов вычисления. Измените вызовы на , tst.awk
чтобы awk -v seed="$RANDOM" -f tst.awk
получать разные случайные числа, генерируемые при каждом вызове.
решение2
Обновленный скрипт, поскольку bc
он не очень хорошо сочетался с ведущими знаками в числах, поэтому был изменен awk
на domath
.
Также изменено использование 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