我有一个数据看起来像这样:
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
之后,我根据“simulation1”列上的值对“ID”和“pheno”列进行排序,然后计算前 40% 行的“pheno”平均值,即 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
然后,我根据“simulation2”列上的值对“ID”和“pheno”列进行排序,然后计算前 40% 行的“pheno”平均值,即 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”列中创建新值。我使用函数 RAND()* 在 Excel 中的“simulation1”和“simulation2”中创建值。但我不可能重复1000遍。我想知道如何在 linux 中创建一个我想要的循环。
最终输出将是:
row_name top40%average_simulate1 top40%average_simulate2 difference
1 0.193 0.1 -0.093
2
.
.
.
1000
答案1
在所有情况下,| column -t
仅添加以下内容以使输出在视觉上对齐。
1)我应该创建两列,分别命名为“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)之后,我根据“simulation1”列上的值对“ID”和“pheno”列进行排序
$ 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) 然后我计算前 40% 行的“pheno”平均值
$ 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 提供了相同的种子,以便输出保持不变,以便于跟踪整个计算阶段。更改对 to 的调用,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