시뮬레이션된 값을 사용하여 두 열의 순서를 동시에 1000번 무작위로 변경하는 방법은 무엇입니까?

시뮬레이션된 값을 사용하여 두 열의 순서를 동시에 1000번 무작위로 변경하는 방법은 무엇입니까?

다음과 같은 데이터가 있습니다.

    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" 열에는 새 값을 만들어야 합니다. 엑셀에서 "simulation1"과 "simulation2"에 값을 생성하기 위해 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) 난수를 포함하는 "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에 제공하여 전체 계산 단계를 더 쉽게 추적할 수 있도록 했습니다. 호출마다 다른 난수가 생성 tst.awk되도록 호출을 로 변경합니다 .awk -v seed="$RANDOM" -f tst.awk

답변2

업데이트된 스크립트는 숫자 bc의 선행 기호와 잘 작동하지 않아 .awkdomath

또한 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

관련 정보