481974개의 행이 있는 "snp_sol"이라는 다음 데이터 세트가 있습니다.
trait effect snp chr pos snp_effect weight variance_explained var_a_hat
1 2 1 1 54 0.2030156E-02 1.251482 0 0
1 2 2 1 689 -0.3726744E-03 0.9660012 0 0
1 2 3 1 1234 0.4801369E-03 0.9823542 0 0
1 2 4 1 1280 -0.1104844E-03 0.9272357 0 0
1 2 5 1 2610 -0.1296295E-02 1.115933 0 0
... ... ... ... ... ... ... ... ...
1 2 481971 26 4897157 -0.7846317E-04 0.9226092 0 0
1 2 481972 26 4898314 -0.3934468E-03 0.9691408 0 0
1 2 481973 26 4898376 -0.7204678E-03 1.019935 0 0
1 2 481974 26 4898606 -0.1522481E-03 0.9333048 0 0
다음과 같이 원래 값의 위치에 나타나야 하는 일곱 번째 열(가중치)에서 각 50개 값(창)의 평균을 구하고 싶습니다.
trait effect snp chr pos snp_effect weight variance_explained var_a_hat
1 2 1 1 54 0.2030156E-02 mean of first 50 rows 0 0
... ... ... ... ... ... ... ... ...
1 2 50 1 4234 0.5801369E-03 mean of first 50 rows 0 0
1 2 51 1 5080 -0.5048544E-03 mean of second set of 50 rows 0 0
... ... ... ... ... ... ... ... ...
1 2 100 1 12050 -0.4854433E-03 mean of second set of 50 rows 0 0
1 2 101 1 14080 -0.3554433E-03 mean of third set of 50 rows 0 0
... ... ... ... ... ... ... ... ...
1 2 150 1 14080 -0.7894433E-03 mean of third set of 50 rows 0 0
and so on
1 2 481974 26 4898606 -0.1522481E-03 mean of last rows 0 0
겹치는 창이 없어야 하며 마지막 창에는 50개의 행이 있을 수 없습니다.
나는 이 코드를 시도하고 있습니다 :
NR=$(wc -l "snp_sol" | awk '{print $1}') # Count the number rows
window=$((NR/50)) # Defining the number windows
int=${window%.*} # Converting to interger
it=$((2*int)) # Double the number of windows
for i in $(seq 0 50 $it) # for statement with a seq to count the windows
do
vi=$i # Variable to define the beginning of the window
vf=$((vi+50)) # Variable to define the end of window
awk -v vi="$vi" -v vf="$vf" '{ if(NR > vi && NR <= vf) # take each window
print } ' snp_sol > b.txt # new temporary file to receive the window
m=$(awk '{sum+=$7} END {m=sum/NR; print m}' b.txt) # Calculate the mean
awk -v mean="$m" '{print $1=$3,$2=mean}' b.txt > $i.temp # save a temporary file with the mean in second column
rm b.txt # Remove the file created to calculate the mean
done
cat *.temp > b.temp # join all temporary files in sequence
paste snp_sol b.temp > c.temp
awk '{print $1,$2,$3,$4,$5,$6,$7=$11,$8,$9=$10}' c.temp > snp_sol
rm *.temp
그러나 이것은 작동하지 않습니다. 이 작업을 수행하는 다른 방법이 있어야 하는데 방법을 모르겠습니다.
이 상황에 대한 가장 좋은 해결책은 쉘 스크립트를 사용하는 것입니다.
도와 주실 수 있으신가요?
미리 감사드립니다.
답변1
GNU datamash
, split
(GNU coreutils) 및 다음을 사용하십시오 awk
.
#!/bin/bash
# remove header line and split `input_file` into n files `split00000`, `split00001`...
# with max. 4 lines each (use `-l50` for your data file)
split -d -a5 -l4 <(tail -n+2 input_file) split
{ head -n1 input_file # add header
for fsplit in split*; do
mean=$(datamash -W mean 7 < "$fsplit") # calculate mean value
awk -v mean="$mean" '{ print $1,$2,$3,$4,$5,$6,mean,$8,$9 }' "$fsplit"
done
} | column -t > output_file # format as table and write result
rm split* # cleanup
이 스크립트에서는 데이터(점선 제거)를 입력으로 사용하고 4개의 값만 평균으로 사용합니다. 스크립트의 데이터 파일 로
바꿉니다 . 그것은 당신이 하는 것과 거의 똑같습니다. 나는 모든 일을 그냥 놔두고 수행합니다 .-l4
-l50
split
datamash
입력 파일:
$ cat input_file
trait effect snp chr pos snp_effect weight variance_explained var_a_hat
1 2 1 1 54 0.2030156E-02 1.251482 0 0
1 2 2 1 689 -0.3726744E-03 0.9660012 0 0
1 2 3 1 1234 0.4801369E-03 0.9823542 0 0
1 2 4 1 1280 -0.1104844E-03 0.9272357 0 0
1 2 5 1 2610 -0.1296295E-02 1.115933 0 0
1 2 481971 26 4897157 -0.7846317E-04 0.9226092 0 0
1 2 481972 26 4898314 -0.3934468E-03 0.9691408 0 0
1 2 481973 26 4898376 -0.7204678E-03 1.019935 0 0
1 2 481974 26 4898606 -0.1522481E-03 0.9333048 0 0
결과:
$ cat output_file
trait effect snp chr pos snp_effect weight variance_explained var_a_hat
1 2 1 1 54 0.2030156E-02 1.031768275 0 0
1 2 2 1 689 -0.3726744E-03 1.031768275 0 0
1 2 3 1 1234 0.4801369E-03 1.031768275 0 0
1 2 4 1 1280 -0.1104844E-03 1.031768275 0 0
1 2 5 1 2610 -0.1296295E-02 1.0069045 0 0
1 2 481971 26 4897157 -0.7846317E-04 1.0069045 0 0
1 2 481972 26 4898314 -0.3934468E-03 1.0069045 0 0
1 2 481973 26 4898376 -0.7204678E-03 1.0069045 0 0
1 2 481974 26 4898606 -0.1522481E-03 0.9333048 0 0
답변2
awk -v mod=50 '
BEGIN{ if(!mod) {mod=50} };
NR==1 {print;next};
(NR+1) % mod == 0 {
$7=sum/count;
print;
sum=count=0;
next;
};
{count++; sum+=$7}
END {
if (((NR+1) % mod)) != 0) {
$7=sum/count;
print;
};
}' snp_sol
이렇게 하면 헤더 행이 수정되지 않은 채 인쇄됩니다. 그런 다음 50개의 입력 행마다 $7의 값을 계산된 평균으로 바꾸고 행을 인쇄합니다. 최종 입력 라인에서도 동일한 작업을 수행합니다.만약에 그리고 만약에이전에 인쇄된 적이 없습니다.
다른 모든 입력 라인의 경우에는 증가하고 count
(행 카운터) $7
( sum
해당 입력 라인을 포함하는 블록의 모든 $7 값의 합계 mod
)에 추가됩니다.
임시 파일이 없고, 동일한 데이터가 다시 실행되지 않으며, awk
셸 루프가 여러 번 분기되지 않습니다. 매우 간단한 알고리즘을 사용하여 입력 파일을 반복하면 됩니다.
mod
참고: 계수로 50을 하드코딩하는 대신 명명된 변수를 사용하십시오 . 명령줄에 지정되지 않은 경우 기본값은 50입니다 -v mod=n
.