제로섬이 있는 열 삭제

제로섬이 있는 열 삭제

숫자 테이블이 있습니다. 즉, 모든 셀에 숫자가 있습니다. 숫자가 아닌 헤더와 행 이름이 있는 탭으로 구분된 파일입니다. 합이 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 ;} }모든 행(열 이름 포함)을 저장합니다.
  • ENDcount != 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

awksed합계가 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원하는 열만 인쇄합니다.

관련 정보