시뮬레이션 값을 사용하여 두 열의 순서를 동시에 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" 열에 새 값을 만들어야 합니다. 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숫자의 선행 기호와 잘 작동하지 않아 업데이트된 스크립트 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

관련 정보