숫자 테이블이 있습니다. 즉, 모든 셀에 숫자가 있습니다. 숫자가 아닌 헤더와 행 이름이 있는 탭으로 구분된 파일입니다. 합이 0이 되는 모든 열을 삭제해야 합니다. 첫 번째 열(행 이름)과 제거되지 않은 나머지 열의 헤더를 유지하고 싶습니다.
입력하다
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
비슷한 질문이지만 다음 줄이 있습니다.합계가 0인 행 삭제
앗해결책은 좋을 것입니다. 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
첫 번째 열이 행 이름이면 그것부터 시작할 수 있습니다.- 부동 소수점 숫자에 주의하세요. 그 합이 0이 아닐 수도 있습니다.
이렇게 하면 원본 파일에서 행을 제거하는 대신 해당 행이 출력됩니다.
답변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..$.)
}'
그러면 전체 파일이 메모리에 로드됩니다. 이를 방지하려면 파일에 두 번 전달해야 합니다.
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'
답변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
이는 파일을 두 번 읽습니다. awk
합계가 0이 아닌 열 번호를 가져온 다음 이를 사용하여 cut
원하는 열만 인쇄합니다.