Supprimer les colonnes qui totalisent zéro

J'ai un tableau numérique, c'est-à-dire que toutes les cellules ont des nombres. Il s'agit d'un file délimité par des tabulations, avec des en-têtes et des noms de ligne non numériques. J'ai besoin de supprimer toutes les colonnes qui ajoutent zéro. Je voudrais garder la première colonne (noms de lignes), et les en-têtes des autres colonnes qui n'ont pas été supprimées.

Consortingbution

abcd e 1 2 0 f 3 4 0 g 5 6 0 

Sortie

 abc e 1 2 f 3 4 g 5 6 

Problème analogue mais avec des lignes: supprimer les lignes qui sum à zéro

awk solution serait génial; Je veux éviter de charger d'énormes files dans R.

enlever la colonne

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 ;} } { for(i=1;i<=NF;i++) { line[NR][i]=$i ; col[i]+=$i ;} } stocke toutes les lignes (y compris les noms de colonnes).
  • END clause END imprime toutes les colonnes si count! = 0.
  • prenez garde que toutes datatables sont conservées en memory.

tester:

 awk -f c.awk a abc e 1 2 f 3 4 g 5 6 

pour la solution en ligne …

essayer

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

  • NR==1 {print } tête d'printing
  • NR>1 { s=0 ; for(i=1;i<=NF;i++) s+=$i ; if (s) print ;} NR>1 { s=0 ; for(i=1;i<=NF;i++) s+=$i ; if (s) print ;} teste pour 0 et imprime si non
  • vous pouvez commencer avec i=2 si la première colonne est le nom de la ligne.
  • Méfiez-vous des nombres à floating point, ils peuvent ne pas résumer jusqu'à 0.

notez que cela va afficher les lignes, pas supprimer du file d'origine.

Il peut être plus facile avec perl si vous voulez garder l'espacement:

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

Cela charge tout le file en memory. Pour éviter cela, vous aurez besoin de deux passes dans le file.

Cela pourrait être fait avec une combinaison de awk et 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 générant le script sed pour supprimer les colonnes dont la sum est 0. Les commands sed s/[^[:blank:]]\{1,\}[[:blank:]]*//3 supprimeraient les colonnes tout en préservant l'espacement des autres colonnes, mais serait assez cher, vous voudrez peut-être faire ce ssortingpping en perl si la performance est un problème.

Pour les lignes, c'est beaucoup plus facile:

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

Comme ces valeurs sont toujours des entiers, vous pouvez faire quelque chose comme:

 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 

cela lit le file deux fois: awk obtient les numéros de colonne où la sum n'est pas nulle; ceux-ci sont ensuite utilisés avec la cut pour imprimer uniquement les colonnes souhaitées.