数値テーブルがあります。つまり、すべてのセルに数字があります。数値ではなく、ヘッダーと行名を持つタブ区切りファイル。合計がゼロになるすべての列を削除する必要があります。最初の列(行名)と削除されていない残りの列のヘッダーを保持したいと思います。
入力する
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
同様の質問ですが、次の行があります。合計がゼロの行を削除
アッ解決策は良いでしょう。 Rから大容量ファイルをロードするのを避けたいです。
答え1
削除する柱
奇妙な:
{ 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
最初の列が行名であれば、それから始めることができます。- 浮動小数点数に注意してください。その合計がゼロではない可能性があります。
これにより、元のファイルから行を削除するのではなく、その行が出力されます。
答え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
合計がゼロの列を削除するスクリプトを生成します。このコマンドは、他の列の間隔を維持しながらその列を削除しますが、高価でパフォーマンスが問題の場合はs/[^[:blank:]]\{1,\}[[:blank:]]*//3
sed
削除する必要があります。perl
行の場合ははるかに簡単です。
perl -MList::Util=sum -lane 'print if $. == 1 or sum @F'
答え3
値は常に整数なので、次のことができます。
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
印刷します。