
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
次のように、元の値の位置に表示される7番目の列(重み)から、各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
。