2015-09-25 6 views
6

Vorrei verificare se due righe iniziano con lo stesso numero nella prima colonna, se ciò accade, allora il dovrebbe essere visualizzata la media della 2a colonna. Esempio file:Verifica se due righe iniziano con lo stesso carattere, in tal caso la media di uscita, in caso contrario, stampa il valore attuale

01 21 6 10%  93.3333% 
01 22 50 83.3333% 93.3333% 
02 20.5 23 18.1102% 96.8504% 
02 21.5 100 78.7402% 96.8504% 
03 22.2 0 0%  100% 
03 21.2 29 100%  100% 
04 22.5 1 5.55556% 100% 
04 23.5 17 94.4444% 100% 
05 22.7 9 7.82609% 100% 
05 21.7 106 92.1739% 100% 
06 23 11 17.4603% 96.8254% 
06 22 50 79.3651% 96.8254% 
07 20.5 14 18.6667% 96% 
07 21.5 58 77.3333% 96% 
08 21.8 4 100%  100% 
09 22.6 0 0%  100% 
09 21.6 22 100%  100% 

Ad esempio, le prime due righe iniziano con 01, ma c'è solo una linea iniziano 08 (linea 15). Pertanto, l'uscita sulla base di questi due casi dovrebbe essere:

01 21.5 
... 
... 
... 
08 21.8 
... 
... 
... 

ho finito con la seguente riga di awk, che funziona grande quando il file ha sempre due linee simili, ma non è riuscito utilizzando il file mostrato sopra (perché la linea 15):

awk '{sum+=$2} (NR%2)==0{print sum/2; sum=0;}' 

Ogni suggerimento è accolto,

risposta

4

Questo awk dovrebbe funzionare:

awk 'function dump(){if (n>0) printf "%s%s%.2f\n", p, OFS, sum/n} 
    NR>1 && $1 != p{dump(); sum=n=0} {p=$1; sum+=$2; n++} END{dump()}' file 
01 21.5 
02 21.0 
03 21.7 
04 23.0 
05 22.2 
06 22.5 
07 21.0 
08 21.8 
09 22.1 

Spiegazione: Stiamo usando 3 variabili:

p -> to hold previous row's $1 value 
n -> count of similar $1 values 
sum -> is sum of $2 values for similar $1 rows 

Come funziona:

NR>1 && $1 != p  # when row #1 > 1 and prev $1 is not current $1 
dump()    # function is to print formatted value of $1 and average 
p=$1; sum+=$2; n++ # sets p to $1, adds current $2 to sum and increments n 
+1

Questo eseguirà il core dump su un file vuoto. –

+0

@EdMorton Sarei interessato ad altre informazioni su questa possibilità EdMorton, grazie per averlo indicato. – Gery

+0

@anubhava grazie per la risposta, spiegheresti come funziona? grazie ancora! – Gery

4

Utilizzando GNU awk

gawk ' 
    {sum[$1]+=$2; n[$1]++} 
    END { 
     PROCINFO["sorted_in"] = "@ind_num_asc" 
     for (key in sum) print key, sum[key]/n[key] 
    } 
' file 
01 21.5 
02 21 
03 21.7 
04 23 
05 22.2 
06 22.5 
07 21 
08 21.8 
09 22.1 

La riga "PROCINFO" rende l'array traversal ordinato il mio indice numericamente. Altrimenti l'output apparirebbe casuale.

+0

Questo risolve anche il problema quando l'ingresso è non ordinato o quando qualche numero appeurs più di due volte. La domanda non è davvero chiara cosa dovrebbe accadere quando il primo numero si presenta una terza volta, questa sembra la soluzione desiderata. –

+0

@WalterA grazie per averlo indicato, ma nel mio caso non ottengo più di due valori simili nella prima colonna, ma molto probabilmente diverse righe "univoche". Penso di aver bisogno di più test per ri-scegliere la risposta giusta. – Gery

+0

@glennjackman grazie per la tua risposta, sarebbe fantastico avere qualche informazione in più su come funziona, grazie ancora! – Gery

1

awk con specie pipe

awk '{s[$1]+=$2;c[$1]++} END{for(i in s) print i, s[i]/c[i]}' file | sort 
+0

grazie per la tua risposta, questa è più corta delle altre, ti dispiacerebbe spiegarlo per favore? Grazie! – Gery

+0

sommano i valori indicizzati dal campo 1 (chiave) e tengono traccia dei conteggi nelle matrici s (um) e c (ount); quando tutti i record sono terminati (blocco END), stampare la chiave e la media per tutte le chiavi. L'array hashing mischia l'ordine degli elementi, ma dal momento che hai l'ordinamento naturale, l'ordinamento lo risolverà. – karakfa

+1

@Gery - è più breve perché il comando awk usa un solo carattere anziché i nomi di variabili multi-carattere, memorizza ogni '$ 1' in memoria due volte e produrrà l'output in un ordine diverso da quello in cui è stato immesso, quindi la necessità di un tubo aggiuntivo e ordinamento. –

1
awk ' 
second{ 
    if($1 == first){ 
     print (second + $2)/2 
     second = 0 
     next 
    } 
    else 
     print second 
} 
{ 
    printf "%s ", $1 
    fist = $1 
    second = $2 
} 
END{ 
    if(second) 
     print second 
}' file 
Problemi correlati