web-dev-qa-db-ja.com

合計がゼロになる列を削除します

私は数値テーブルを持っています。つまり、すべてのセルに数値があります。これはタブ区切りのファイルであり、数値以外のヘッダーと行名が含まれています。合計がゼロになるすべての列を削除する必要があります。最初の列(行名)と、削除されなかった残りの列のヘッダーを保持したいと思います。

入力

a  b  c  d
e  1  2  0
f  3  4  0
g  5  6  0

出力

a  b  c
e  1  2
f  3  4
g  5  6

同様の問題ですが、行があります: 合計がゼロになる行を削除します

awkソリューションは素晴らしいでしょう。 Rに巨大なファイルをロードしないようにしたい。

3
fibar

削除するには

c.awk:

_ { for(i=1;i<=NF;i++) { line[NR][i]=$i ; col[i]+=$i ;} }
END {
 for ( l=1 ; l<=NR ; l++ )
  {
    printf line[l][1]   "\t" ;
    for (c=2;c<=NF;c++) if (col[c]) printf line[l][c]  "\t" ;
    printf "\n" ;
  }
}
_

どこ

  • { for(i=1;i<=NF;i++) { line[NR][i]=$i ; col[i]+=$i ;} }すべての行(列名を含む)を格納します。
  • END句は、count!= 0の場合、すべての列を出力します。
  • すべてのデータがメモリに保持されることに注意してください。

テスト:

_awk -f c.awk a
a   b       c
e   1       2
f   3       4
g   5       6
_

ラインソリューションの場合.。

試してみてください

_ awk 'NR==1 {print } NR>1 { s=0 ; for(i=1;i<=NF;i++) s+=$i ; if (s) print ;}'
_

どこ

  • _NR==1 {print }_印刷ヘッダー
  • NR>1 { s=0 ; for(i=1;i<=NF;i++) s+=$i ; if (s) print ;} 0をテストし、そうでない場合は出力
  • 最初の列が行名の場合は、_i=2_で始めることができます。
  • 浮動小数点数に注意してください。合計が0にならない場合があります。

これは元のファイルから削除するのではなく、行を出力することに注意してください。

2
Archemar

間隔を維持したい場合は、Perlを使用すると簡単な場合があります。

Perl -lne '
   $i = 0;
   for (/\S+\s*/g) {
      $cell[$.][$i] = $_;
      $sum[$i++] += $_
   }
   END{
     @keep=(0, grep {$sum[$_]} (1..$#sum));
     print((@{$cell[$_]})[@keep]) for (1..$.)
   }'

これにより、ファイル全体がメモリにロードされます。これを回避するには、ファイルに2つのパスが必要です。

これは、awksedの組み合わせで実行できます。

awk '
  NR>1{for (i=2; i<=NF; i++) sum[i]+=$i; if (NF>n) n = NF}
  END {
    for (;n>1;n--)
      if (!sum[n])
        print "s/[^[:blank:]]\\{1,\\}[[:blank:]]*//" n
  }' < file | sed -f - file

awksedスクリプトを生成して、合計が0の列を削除します。s/[^[:blank:]]\{1,\}[[:blank:]]*//3sedコマンドは、他の列の間隔を維持しながら列を削除しますが、非常にコストがかかるため、パフォーマンスが問題になる場合は、Perlでその除去を行うことをお勧めします。

行の場合、それははるかに簡単です:

Perl -MList::Util=sum -lane 'print if $. == 1 or sum @F'
1

これらの値は常に整数であるため、次のようなことができます。

cut $(awk 'NR>1{for(i=2;i<=NF;i++) s[i]+=$i}END{printf("%s", "-f 1");
for (i=2;i<=NF;i++) {if (s[i]) printf(",%s", i)}}' infile) infile

これにより、ファイルが2回読み取られます。awkは、合計がゼロでない列番号を取得します。次に、これらをcutとともに使用して、目的の列のみを出力します。

0
don_crissti