separador print examples comparar columnas campos archivos linux bash awk mean missing-data

linux - print - Calcula la media de cada columna ignorando los datos faltantes con awk



awk separador de campos (2)

Tengo una gran tabla de datos separados por tabulaciones con miles de filas y docenas de columnas y tiene datos faltantes marcados como "na". Por ejemplo,

na 0.93 na 0 na 0.51 1 1 na 1 na 1 1 1 na 0.97 na 1 0.92 1 na 1 0.01 0.34

Me gustaría calcular la media de cada columna, pero asegurándome de que los datos faltantes sean ignorados en el cálculo. Por ejemplo, la media de la columna 1 debe ser 0,97. Creo que podría usar awk pero no estoy seguro de cómo construir el comando para hacer esto para todas las columnas y dar cuenta de los datos faltantes.

Todo lo que sé hacer es calcular la media de una sola columna, pero trata los datos faltantes como 0 en lugar de dejarlos fuera del cálculo.

awk ''{sum+=$1} END {print sum/NR}'' filename


Esto es oscuro, pero funciona para tu ejemplo

awk ''{for(i=1; i<=NF; i++){sum[i] += $i; if($i != "na"){count[i]+=1}}} END {for(i=1; i<=NF; i++){if(count[i]!=0){v = sum[i]/count[i]}else{v = 0}; if(i<NF){printf "%f/t",v}else{print v}}}'' input.txt

EDITAR: Así es como funciona:

awk ''{for(i=1; i<=NF; i++){ #for each column sum[i] += $i; #add the sum to the "sum" array if($i != "na"){ #if value is not "na" count[i]+=1} #increment the column "count" } #endif } #endfor END { #at the end for(i=1; i<=NF; i++){ #for each column if(count[i]!=0){ #if the column count is not 0 v = sum[i]/count[i] #then calculate the column mean (here represented with "v") }else{ #else (if column count is 0) v = 0 #then let mean be 0 (note: you can set this to be "na") }; #endif col count is not 0 if(i<NF){ #if the column is before the last column printf "%f/t",v #print mean + TAB }else{ #else (if it is the last column) print v} #print mean + NEWLINE }; #endif }'' input.txt #endfor (note: input.txt is the input file)

`` `


Una posible solución:

awk -F"/t" ''{for(i=1; i <= NF; i++) {if($i == $i+0){sum[i]+=$i; denom[i] += 1;}}} END{for(i=1; i<= NF; i++){line=line""sum[i]/(denom[i]?denom[i]:1)FS} print line}'' inputFile

El resultado para los datos dados:

0.973333 0.9825 0 0.7425 0.01 0.7125

Tenga en cuenta que la tercera columna contiene solo "na" y la salida es 0 . Si desea que la salida sea na , cambie el bloque END{...} a:

END{for(i=1; i<= NF; i++){line=line""(denom[i] ? sum[i]/denom[i]:"na")FS} print line}''