マシンから名前を読みましたが、時にはこれらの読み取り値が重複することがあります。
読み取り値がない場合は空白のままにしてください。
Name Instrument Rep R1 R2 R3
N1 I1 1 1 2 3
N2 I1 1 1 3 4
N1 I1 2 2 3 4
N3 I1 2 3 4 5
N1 I2 1 1 2 3
N2 I2 1 1 3 4
N2 I2 2 2 3 4
N3 I2 1 3 4 5
N1 I3 1 1 4
N2 I3 1 2 5
N3 I3 1 6
N3 I3 2 1
まず、平均値(名前別、場所別)を使用して重複項目をマージしたいと思います。それからこのデータを転置し、.
欠けている値を点()に置き換えたいと思います。
私が望む出力は
Reading Instrument N1 N2 N3
R1 I1 1.5 1 3
R2 I1 2.5 3 4
R3 I1 3.5 4 5
R1 I2 1 1.5 3
R2 I2 2 3 4
R3 I2 3 4 5
R1 I3 1 2 .
R2 I3 . 5 6
R3 I3 4 . 1
名前と読み取り値の数は非常に異なります。一部のファイルには134個の読み取り値があり、他のファイルには28個などがありますが、読み取り値は常に列3から始まります。
成功せずに1つの列でのみテストを実行しようとした方法は次のとおりです。
awk '
NR>1{
arr[$1" "$2" "$3] += $4
count[$1" "$2" "$3] += 1
}
END{
for (a in arr) {
print a, arr[a] / count[a]
}
}
' file | awk '
NR == 1 {
n = NF
for (i = 1; i <= NF; i++)
row[i] = $i
next
}
{
if (NF > n)
n = NF
for (i = 1; i <= NF; i++)
row[i] = row[i] " " $i
}
END {
for (i = 1; i <= n; i++)
print row[i]
}'
答え1
単純な/を使って実際にsed
やりたい場合はawk
実際に可能です。
〜のように言及する渡すジョーSPACE
、フィールド区切り文字として使用されます&データ価値が問題だawk
。
そのため、sed
まずデータ型を再指定することをお勧めします。
sed 's/ *$//'
SPACE
行の末尾からsを削除します(最初の行を除くすべての入力行はsで終わるSPACE
ため、入力は正規化され、各行の終わりに欠けている可能性のある値は削除されます)。
次に、隣接するsの各ペアの間にaを挿入しますsed 's/ / . /g/'
(行の終わりにない潜在的な欠損値を埋める)。.
SPACE
これはSPACE
、隣接する欠損値がある場合は追加のsを挿入するため、sed 's/ / /g'
これらの値を再度削除するために使用する必要があります。
その後、awk
最初の行(ヘッダーなど)を使用して読み取り名と数を知り、各行の末尾に潜在的な欠落値を追加し(他のすべての値は処理されますsed
)、すべての読み取りと合計を合計することができます。その名前とデバイスを追跡し、希望の方向/順序で平均(存在する場合)を出力します。
sed -e 's/ *$//' -e 's/ / . /g' -e 's/ / /g' <<< 'Name Instrument Rep R1 R2 R3
N1 I1 1 1 2 3
N2 I1 1 1 3 4
N1 I1 2 2 3 4
N3 I1 2 3 4 5
N1 I2 1 1 2 3
N2 I2 1 1 3 4
N2 I2 2 2 3 4
N3 I2 1 3 4 5
N1 I3 1 1 4
N2 I3 1 2 5
N3 I3 1 6
N3 I3 2 1' | awk '
# get number of readings/fields
NR==1{for(i=4;i<=NF;++i)readings[i-4]=$i;fields=NF;next}
# add missing fields in the end
{for(i=NF+1;i<=fields;++i)$i="."}
# keep track of names & instruments
names[$1];instruments[$2]
# sum & count readings per name/instrument (ignoring missing ["."] values)
{for(i=4;i<=NF;++i)if($i!="."){sum[readings[i-4] FS $2 FS $1]+=$i;++count[readings[i-4] FS $2 FS $1]}}
# after reading all data:
END{
# print header
printf "Reading"FS"Instrument";for(name in names)printf FS name;print ""
# sort output rows by instrument
for(instrument in instruments){
# keep order of readings
for(i=0;i<length(readings);++i){
# print first two columns
printf readings[i] FS instrument
# remaining columns (i.e. names):
for(name in names){
# if data available:
if(count[readings[i] FS instrument FS name]){
# print average
printf FS sum[readings[i] FS instrument FS name]/count[readings[i] FS instrument FS name]
# otherwise:
}else{
# print missing value ["."]
printf FS "."
}
# proceed with next row
}print ""
}
}
}
'
注:私の考えでは、多次元FS
配列の索引付けで区切り文字として使用することがほとんどの場合、最善の選択肢です。なぜなら、すべてのフィールドにこれを含めないことが保証されるからです(配列を繰り返して配列の「次元」を分割する必要がある場合)。 )。ここでは必須ではありませんが、習慣にしました。
編集する:ジョー 指摘名前/楽器の記録方法以前のバージョンこの回答には追加の説明が必要な場合があります。これはk in a
、キーが配列に存在することを確認するのではなく、上記で使用した単純化されたバージョンに触発されました。k
a
いいえa[k]
次の項目を作成します。分配するこのエントリのNULL値(そしてそれを返します)。
私にとって、上記のコードはあなたが要求した出力を生成します。
Reading Instrument N1 N2 N3
R1 I1 1.5 1 3
R2 I1 2.5 3 4
R3 I1 3.5 4 5
R1 I2 1 1.5 3
R2 I2 2 3 4
R3 I2 3 4 5
R1 I3 1 2 .
R2 I3 . 5 6
R3 I3 4 . 1
注:<<<
私が使用する構文はHERE-STRINGです。これはすべてのシェルでは機能しない可能性があります(bash
ただしサポートされています)。入力ファイルパスを渡すとsed
(私が知る限り)、すべてのシェルで動作します。
注:これはすべてのデータがメモリに収まる場合にのみ機能します。それ以外の場合は、入力を最初にソートしてデータを要約するメモリ集約度の低いソリューションが必要です。この場合、行列を転置する方が難しい場合があります。
編集する:
注:出力例とは異なり、私の出力には行の末尾には何も含まれていませんSPACE
。なぜならaを入れる時と入れない時が分からないからですSPACE
。これが意味がある場合は、質問を調整してください。それに応じて回答を更新します。それ以外の場合は、SPACE
期待される出力からこれらを削除することをお勧めします。
答え2
現在の問題は次のとおりです。
1) スペースをフィールド区切り記号と値として同時に使用することはできません。値が固定長(値ごとに1列)の場合は、これを使用できます。欠けている値を0に設定できると簡単になります。ただし、このような場合、欠落は実際には欠落を意味するため、その項目は追加の処理から除外されます。
この方法を使用するには、入力行全体を含めるために$ 0が必要です。 substr($ 0、offset、1)を使用して、オフセットが7、9、11、または13の読み取り値を取得できます(インデックスが0または1から始まるかどうかを忘れました。0の場合、各オフセットから減算して1に移動します。 )。
残りのロジックに役立つ場合は、空の行方不明の読み取りをMなどのプレースホルダーに置き換えることができます。それ以外の場合は、複数のスペースが 1 つのスペースと同じになり、スペースの後ろのすべてのフィールドは、事実上低いフィールド番号に左に移動されます。
欠落がゼロに等しい場合は簡単です。問題のあるスペースをゼロに置き換えることができますが、欠落しているスペースがゼロと異なると、すべての計算が混乱します。
gsub を使用して、2 つの連続した空白と、その後に 3 番目の空白があるすべての項目を置き換えたり、行末を「M」または「0」に置き換えたりできます。
現在の最初のawkでは、増分と合計の前に欠落しているかどうかをテストする必要があります。
2)2番目のawkに空の欠損値がある場合、NFも小さすぎます。他のすべてのアイテムは廃棄されます。
私はあなたの最初のawkが何をしているのか理解していると思いますが、2番目のawkで何を達成したいのかわかりません。
3)この出力を提供したい他のプログラムをなだめるために欠けている値を示すためにドットを使用する必要があるかもしれませんが、通常これは小数点のように見えるので悪い考えです(システムでは正当です)。データ) 一部のソフトウェアでは、ゼロ値として解釈されるか、または一般的に他の解析をよりトリッキーにすることができます。