ほぼ2000行の入力ファイルがあります。計算をして3番目の列に印刷する必要があります。
入力ファイルに関連する操作の例:
n ID1_1 n/(n+k)
k ID1_2
入力ファイル:
10 ID1_1
20 ID1_2
1 ID3_1
9 ID3_2
20 ID20_1
15 ID2_1
300 ID2_2
予想出力:
10 ID1_1 0.33
20 ID1_2
200 ID3_1 0.11
9 ID3_2
20 ID20_1 /*I would just leave it like that*/
15 ID2_1 0.047
300 ID2_2
簡単な解決策がありますか?ありがとうございます。
答え1
表示された入力を考慮すると、次のことが機能します。
<infile sed -e '$!N;2i\' -e '3k
s|\(\(.* *\).*_1\)\n\(\(.* *\).*_2\)$|[\1 ]P\2d\4+/p[\3]pc|;t
s|^[ _ID0-9]*|[&]pc|;P;D' | dc
私のために印刷されます...
10 ID1_1 .333
20 ID1_2
1 ID3_1 .100
9 ID3_2
20 ID20_1
15 ID2_1 .047
300 ID2_2
...dc
精度を3に設定しましたが、精度が10だからです...
10 ID1_1 .3333333333
20 ID1_2
1 ID3_1 .1000000000
9 ID3_2
20 ID20_1
15 ID2_1 .0476190476
300 ID2_2
出力精度に加えて、あなたの精度とは異なります。期待される出力3行目 - しかし、これは質問のタイプミスのためのようです。
とにかく、これを理解するには、まず出力を2つの形式に解析する必要があることを考慮する必要があります。dc
次のewlineなしでaを印刷するdc
か、数字または1でaを印刷します。マクロで実行する以外は文字列として何もできません。しかし、数値を見ると非常に能力に優れています。P
[string]
\n
p
[string]
x
dc
したがって、現在の行が最後の行の場合は、sed
まず$!N
現在の行に追加の行を追加します。 2行目はstdoutに文字列を挿入します。これは精度を3に設定するコマンドです。!
$
i
3k
dc
その後、交換しようとしています。
s|\(\(.* *\).*_1\)\n\(\(.* *\).*_2\)$|[\1 ]P\2d\4+/p[\3]pc|
_1
これは、パターンスペースに現在少なくとも1つのスペースが含まれている場合にのみ成功します。ある地点ではすぐ後ろに並んだ文字が続き\n
、ある地点ではその後に少なくとも1つの空白が続き、ある地点では直後に末尾が_2
続き$
ます。パターン空間の
これは、上記の置換が次の行のペアにのみ影響することを意味します。
...ID_1
...ID_2
...他の人でもありません。影響がある場合は、コンテンツを利用可能なdc
スクリプトに変換します。次に、t
交換が成功したことを確認し、成功すると、スクリプトから分岐して交換結果を印刷し、sed
コマンドを実行しなくなります。標準出力を標準入力としてdc
使用するため、たとえば、最初の2行を次のように変更します。sed
sed
[ 10 ID_1 ]P10d20+/p[ 20 ID_2]pc
...dc
次に、その入力を次のように処理します。
[ 10 ID_1 ]
- 角かっこの間の文字列をスタックの一番上にスライドさせます。(これを行うと、すでにスタック内のすべてのアイテムが1つ下にプッシュされます。)P
P
- 後ろに並んでいないスタックの上部を印刷して\n
ポップします。(これを行うと、下のスタックのすべての値が1ずつ増加します。)10
- 数字10をスタックの一番上にスライドさせます。d
d
- スタックの上部をコピーします。20
- 数字20をスタックの一番上にスライドさせます。+
- スタックの上部に2cdを追加し、スタックの上部に2cdを追加します。(2つを同時に爆発させる)そして結果をスタックの一番上にスライドさせます。/
- スタックの上から2cdを分割します。(今私たちはd
コピーします10
)スタックの上から(私たちの10 20 +
結果) (2つを同時に爆発させる)そして結果をスタックの一番上にスライドさせます。p
p
- スタックの上部を印刷します。(揚げずに)その後に行が表示されます\n
。[ 20 ID_2]
- 文字列をスタックの一番上にスライドさせます。p
p
- スタックの上部を印刷します。(もう一度言うが爆発しないでください)その後は\n
Ewlineが続くc
c
- スタックを理解する
したがって、dc
以下を印刷してください。
10 ID1_1 .333
20 ID1_2
ただし、sed
すでに説明したように、成功した一致がなく、パターンスペースが変更された場合、処理する他の行が残ります。この場合、sed
コマンドを追加してからの間に最初のシーケンスを挿入することもできます。次に、パターンスペースから最初に表示されるewlineまでパターンスペースを印刷し、残りの部分から始める前に同じ内容を削除します。したがって、全体的に1行の予測が実行され、ジョブスクリプトは常に印刷されます。[ ID_0-9]*
[
]
pc
P
\n
D
sed
dc
dc
これは、ファイル全体がストリームで処理されることを意味します。これは`dc
とsed
` の両方が処理されると出力を提供するからです。これにより、入力が質問の例と似ている場合は、同じ方法で200万行を簡単に処理したり、リアルタイムでログファイルを処理したりできます。
答え2
Pythonで。
#!/usr/bin/python3
import re
import sys
fil = sys.argv[1]
with open(fil) as f:
m = re.split(r'[\n\r]+(?= *\d+\s+ID\d+_1)', f.read())
l = []
for i in m:
l.append(re.sub(r'(?s)^(\s*(\d+)\s+([^_]+)_1)([\n\r]+\s*(\d+)\s+\3_2)$', \
lambda m: m.group(1) + " "+ str(float(m.group(2))/(float(m.group(2))+float(m.group(5)))) + m.group(4),i))
print('\n'.join(l), end = "")
上記のスクリプトを別の名前で保存してscript.py
実行してみてください。
python3 script.py inputfile
例:
$ python3 f.py file
10 ID1_1 0.3333333333333333
20 ID1_2
1 ID3_1 0.1
9 ID3_2
20 ID20_1
15 ID2_1 0.047619047619047616
300 ID2_2
答え3
awk
次のいずれかのコマンドですべての操作を実行できます。
$ awk '{if(NR%2){n=$1;last=$0;}else{print last,n/(n+$1)"\n"$0}}' file
10 ID1_1 0.333333
20 ID1_2
1 ID3_1 0.1
9 ID3_2
15 ID2_1 0.047619
300 ID2_2
アイデアは、単に現在の行が偶数であることを確認することです。 i)その場合は、last
必要な計算で前の行()を印刷し、ii)そうでない場合は、現在の行をlast
最初のフィールドとして保存しますn
。
以下を使用して、印刷される小数点以下の桁数を制御できますprintf
。
$ awk '{if(NR%2){n=$1;last=$0;}else{printf "%s %.2f\n%s\n",last,n/(n+$1),$0}}' file
10 ID1_1 0.33
20 ID1_2
1 ID3_1 0.10
9 ID3_2
15 ID2_1 0.05
300 ID2_2
Perlにも同じ基本内容があります。
$ perl -lane 'if($.%2){$n=$F[0];$last=$_;}
else{printf "%s %.2f\n%s\n",$last,$n/($n+$F[0]),$_}' file
10 ID1_1 0.33
20 ID1_2
1 ID3_1 0.10
9 ID3_2
15 ID2_1 0.05
300 ID2_2
答え4
OP編集後(追加用語を参照):
awk '
/ID.*_1/{
n=$1
idx=$2
sub("_1","_2",idx)
printf s"%s",$0
s="\n"}
$2==idx{
printf " %.2f\n%s",n/(n+$1),$0}
END{
print""}' file