ファイルを転置し、欠落している値を置き換えます。

ファイルを転置し、欠落している値を置き換えます。

マシンから名前を読みましたが、時にはこれらの読み取り値が重複することがあります。

読み取り値がない場合は空白のままにしてください。

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、キーが配列に存在することを確認するのではなく、上記で使用した単純化されたバージョンに触発されました。ka いいえ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期待される出力からこれらを削除することをお勧めします。

おすすめ記事