私は数値テーブルを持っています。つまり、すべてのセルに数値があります。これはタブ区切りのファイルであり、数値以外のヘッダーと行名が含まれています。合計がゼロになるすべての列を削除する必要があります。最初の列(行名)と、削除されなかった残りの列のヘッダーを保持したいと思います。
入力
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に巨大なファイルをロードしないようにしたい。
削除するには列
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
_で始めることができます。これは元のファイルから削除するのではなく、行を出力することに注意してください。
間隔を維持したい場合は、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つのパスが必要です。
これは、awk
とsed
の組み合わせで実行できます。
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
awk
sed
スクリプトを生成して、合計が0の列を削除します。s/[^[:blank:]]\{1,\}[[:blank:]]*//3
sed
コマンドは、他の列の間隔を維持しながら列を削除しますが、非常にコストがかかるため、パフォーマンスが問題になる場合は、Perl
でその除去を行うことをお勧めします。
行の場合、それははるかに簡単です:
Perl -MList::Util=sum -lane 'print if $. == 1 or sum @F'
これらの値は常に整数であるため、次のようなことができます。
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
とともに使用して、目的の列のみを出力します。