다음과 같은 데이터가 있습니다.
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
아래와 같이 임의의 숫자가 포함된 "simulation1" 및 "simulation2"라는 이름의 열 2개를 만들어야 합니다.
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번 반복하는 것은 불가능합니다. 내가 원하는 것을 리눅스에서 어떻게 루프를 만들 수 있는지 궁금합니다.
최종 출력은 다음과 같습니다.
row_name top40%average_simulate1 top40%average_simulate2 difference
1 0.193 0.1 -0.093
2
.
.
.
1000
답변1
아래의 모든 경우에는 | column -t
출력을 시각적으로 정렬하기 위해 추가되었습니다.
1) "simulation1"과 "simulation2"라는 이름의 2개 열을 생성해야 하며 그 안에 임의의 숫자가 포함되어 있어야 합니다.
$ 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에 제공했습니다. 호출할 때마다 생성되는 다른 난수를 얻으려면 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