utility da riga di comando per stampare statistiche di numeri in linux

Spesso mi trovo con un file che ha un numero per riga. Finisco per importarlo in Excel per visualizzare cose come mediana, deviazione standard e così via.

C’è una utility da riga di comando in Linux per fare lo stesso? Di solito ho bisogno di trovare la media, la mediana, la min, la max e la deviazione standard.

Questo è un gioco da ragazzi con R. Per un file che assomiglia a questo:

 1 2 3 4 5 6 7 8 9 10 

Usa questo:

 R -q -e "x <- read.csv('nums.txt', header = F); summary(x); sd(x[ , 1])" 

Per ottenere questo:

  V1 Min. : 1.00 1st Qu.: 3.25 Median : 5.50 Mean : 5.50 3rd Qu.: 7.75 Max. :10.00 [1] 3.02765 

Modifica per aggiungere un paio di commenti chiarificatori (perché sono tornato a questo e non ricordo alcune delle motivazioni):

  • Il flag -q riduce le licenze di avvio e l'output di aiuto di R
  • L'indicatore -e dice a R che passerai un'espressione dal terminale
  • x è un data.frame - una tabella, in pratica. È una struttura che ospita più vettori / colonne di dati, il che è un po 'strano se stai leggendo in un singolo vettore. Ciò ha un impatto su quali funzioni è ansible utilizzare.
  • Alcune funzioni, come summary() , naturalmente ospitano data.frames . Se x avesse più campi, summary() fornirebbe le statistiche descrittive di cui sopra.
  • Ma sd() può prendere solo un vettore alla volta, ed è per questo che indice x per quel comando ( x[ , 1] restituisce la prima colonna di x ). È ansible utilizzare apply(x, MARGIN = 2, FUN = sd) per ottenere le SD per tutte le colonne.

Utilizzando “st” ( https://github.com/nferraz/st )

 $ st numbers.txt N min max sum mean stddev 10 1 10 55 5.5 3.02765 

O:

 $ st numbers.txt --transpose N 10 min 1 max 10 sum 55 mean 5.5 stddev 3.02765 

(DISCLAIMER: Ho scritto questo strumento :))

Per la media, la mediana e la deviazione standard puoi usare awk . Ad esempio il seguente stamperà la media:

 awk '{a+=$1} END{print a/NR}' myfile 

( NR è una variabile awk per il numero di record, $1 indica il primo argomento (separato dallo spazio) della riga ( $0 sarebbe l’intera riga, che funzionerebbe anche qui ma in linea di principio sarebbe meno sicuro, sebbene per il calcolo probabilmente prenderà comunque il primo argomento comunque) e END significa che i seguenti comandi saranno eseguiti dopo aver elaborato l’intero file (uno potrebbe anche aver inizializzato a a 0 in una istruzione BEGIN{a=0} )).

Per il min / max, puoi eseguire il pipe sort & head / tail :

 sort -n myfile | head -n1 sort -n myfile | tail -n1 

Lo strumento Ya che può essere utilizzato per calcolare statistiche e visualizzare la distribuzione in modalità ASCII è ministat . È uno strumento di FreeBSD, ma è anche impacchettato per le diffuse distribuzioni Linux come Debian / Ubuntu.

Esempio di utilizzo:

 $ cat test.log Handled 1000000 packets.Time elapsed: 7.575278 Handled 1000000 packets.Time elapsed: 7.569267 Handled 1000000 packets.Time elapsed: 7.540344 Handled 1000000 packets.Time elapsed: 7.547680 Handled 1000000 packets.Time elapsed: 7.692373 Handled 1000000 packets.Time elapsed: 7.390200 Handled 1000000 packets.Time elapsed: 7.391308 Handled 1000000 packets.Time elapsed: 7.388075 $ cat test.log| awk '{print $5}' | ministat -w 74 x  +--------------------------------------------------------------------------+ | x | |xx xx xxx| | |__________________________A_______M_________________| | +--------------------------------------------------------------------------+ N Min Max Median Avg Stddev x 8 7.388075 7.692373 7.54768 7.5118156 0.11126122 

Sì, si chiama Perl
e qui è conciso one-liner:

 perl -e 'use List::Util qw(max min sum); @a=();while(<>){$sqsum+=$_*$_; push(@a,$_)}; [email protected];$s=sum(@a);$a=$s/@a;$m=max(@a);$mm=min(@a);$std=sqrt($sqsum/$n-($s/$n)*($s/$n));$mid=int @a/2;@srtd=sort @a;if(@a%2){$med=$srtd[$mid];}else{$med=($srtd[$mid-1]+$srtd[$mid])/2;};print "records:$n\nsum:$s\navg:$a\nstd:$std\nmed:$med\max:$m\min:$mm";' 

Esempio

 $ cat tt 1 3 4 5 6.5 7. 2 3 4 

E il comando

 cat tt | perl -e 'use List::Util qw(max min sum); @a=();while(<>){$sqsum+=$_*$_; push(@a,$_)}; [email protected];$s=sum(@a);$a=$s/@a;$m=max(@a);$mm=min(@a);$std=sqrt($sqsum/$n-($s/$n)*($s/$n));$mid=int @a/2;@srtd=sort @a;if(@a%2){$med=$srtd[$mid];}else{$med=($srtd[$mid-1]+$srtd[$mid])/2;};print "records:$n\nsum:$s\navg:$a\nstd:$std\nmed:$med\max:$m\min:$mm";' records:9 sum:35.5 avg:3.94444444444444 std:1.86256162380447 med:4 max:7. min:1 

data_hacks è un’utilità da riga di comando Python per le statistiche di base.

Il primo esempio da quella pagina produce i risultati desiderati:

 $ cat /tmp/data | histogram.py # NumSamples = 29; Max = 10.00; Min = 1.00 # Mean = 4.379310; Variance = 5.131986; SD = 2.265389 # each * represents a count of 1 1.0000 - 1.9000 [ 1]: * 1.9000 - 2.8000 [ 5]: ***** 2.8000 - 3.7000 [ 8]: ******** 3.7000 - 4.6000 [ 3]: *** 4.6000 - 5.5000 [ 4]: **** 5.5000 - 6.4000 [ 2]: ** 6.4000 - 7.3000 [ 3]: *** 7.3000 - 8.2000 [ 1]: * 8.2000 - 9.1000 [ 1]: * 9.1000 - 10.0000 [ 1]: * 

Significare:

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

Mediano:

 gawk -v max=128 ' function median(c,v, j) { asort(v,j); if (c % 2) return j[(c+1)/2]; else return (j[c/2+1]+j[c/2])/2.0; } { count++; values[count]=$1; if (count >= max) { print median(count,values); count=0; } } END { print "median = " median(count,values); }' filename 

Modalità:

 awk '{c[$1]++;} END {for (i in count) {if (c[i]>max) {max=i;}} print "mode = " max;}' filename 

Questo calcolo in modalità richiede un numero pari di campioni, ma vedi come funziona …

Deviazione standard:

 awk '{sum+=$1; sumsq+=$1*$1;} END {print "stdev = " sqrt(sumsq/NR - (sum/NR)**2);}' filename 

Nel caso, c’è datastat , un semplice programma per Linux che calcola statistiche semplici dalla riga di comando. Per esempio,

 cat file.dat | datastat 

genererà il valore medio su tutte le righe per ogni colonna di file.dat. Se è necessario conoscere la deviazione standard, min, max, è ansible aggiungere rispettivamente le --dev , --min e --max .

datastat ha la possibilità di aggregare le righe in base al valore di una o più colonne “chiave”. Per esempio,

 cat file.dat | datastat -k 1 

produrrà, per ogni diverso valore trovato sulla prima colonna (la “chiave”), la media di tutti gli altri valori di colonna come aggregati tra tutte le righe con lo stesso valore sulla chiave. Puoi usare più colonne come campi chiave (es. -K 1-3, -k 2,4 ecc …).

È scritto in C ++, funziona veloce e con poca occupazione di memoria, e può essere collegato bene con altri strumenti come cut , grep , sed , sort , awk , ecc.

Si potrebbe anche considerare l’utilizzo di clistats . Si tratta di uno strumento di interfaccia a riga di comando altamente configurabile per calcolare le statistiche per un stream di numeri di input delimitati.

Opzioni I / O

  • I dati di input possono provenire da un file, da uno standard input o da una pipe
  • L’output può essere scritto su un file, output standard o pipe
  • L’output utilizza intestazioni che iniziano con “#” per abilitare il piping su gnuplot

Opzioni di analisi

  • Rilevamento del segnale, della fine del file o della linea vuota per interrompere l’elaborazione
  • È ansible impostare il carattere di commento e delimitatore
  • Le colonne possono essere filtrate dall’elaborazione
  • Le righe possono essere filtrate dall’elaborazione in base al vincolo numerico
  • Le righe possono essere filtrate dall’elaborazione in base al vincolo della stringa
  • Le righe iniziali dell’intestazione possono essere saltate
  • È ansible elaborare un numero fisso di righe
  • I delimitatori duplicati possono essere ignorati
  • Le righe possono essere rimodellate in colonne
  • Applica rigorosamente che vengono elaborate solo le righe della stessa dimensione
  • Una riga contenente i titoli delle colonne può essere utilizzata per il titolo delle statistiche di output

Opzioni statistiche

  • Statistiche riassuntive (conteggio, minimo, medio, massimo, deviazione standard)
  • covarianza
  • Correlazione
  • Offset quadrati minimi
  • Pendio dei minimi quadrati
  • Istogramma
  • Dati grezzi dopo il filtraggio

NOTA: sono l’autore.

Mi sono ritrovato a voler fare ciò in una pipeline di shell e ottenere gli argomenti giusti per R ha richiesto un po ‘di tempo. Ecco cosa mi è venuto in mente:

seq 10 | R --slave -e 'x <- scan(file="stdin",quiet=TRUE); summary(x)' Min. 1st Qu. Median Mean 3rd Qu. Max. 1.00 3.25 5.50 5.50 7.75 10.00

L'opzione --slave "Make (s) R funziona nel modo più silenzioso ansible ... Implica --quiet e --no-save". L'opzione -e dice a R di trattare la seguente stringa come codice R. La prima istruzione legge dallo standard in e memorizza ciò che viene letto nella variabile chiamata "x". L'opzione quiet=TRUE per la funzione di scan sopprime la scrittura di una riga che indica quanti elementi sono stati letti. La seconda istruzione applica la funzione di summary a x , che produce l'output.

 #!/usr/bin/perl # # stdev - figure N, min, max, median, mode, mean, & std deviation # # pull out all the real numbers in the input # stream and run standard calculations on them. # they may be intermixed with other test, need # not be on the same or different lines, and # can be in scientific notion (avagadro=6.02e23). # they also admit a leading + or -. # # Tom Christiansen # [email protected] use strict; use warnings; use List::Util qw< min max >; # my $number_rx = qr{ # leading sign, positive or negative (?: [+-] ? ) # mantissa (?= [0123456789.] ) (?: # "N" or "N." or "NN" (?: (?: [0123456789] + ) (?: (?: [.] ) (?: [0123456789] * ) ) ? | # ".N", no leading digits (?: (?: [.] ) (?: [0123456789] + ) ) ) ) # abscissa (?: (?: [Ee] ) (?: (?: [+-] ? ) (?: [0123456789] + ) ) | ) }x; my $n = 0; my $sum = 0; my @values = (); my %seen = (); while (<>) { while (/($number_rx)/g) { $n++; my $num = 0 + $1; # 0+ is so numbers in alternate form count as same $sum += $num; push @values, $num; $seen{$num}++; } } die "no values" if $n == 0; my $mean = $sum / $n; my $sqsum = 0; for (@values) { $sqsum += ( $_ ** 2 ); } $sqsum /= $n; $sqsum -= ( $mean ** 2 ); my $stdev = sqrt($sqsum); my $max_seen_count = max values %seen; my @modes = grep { $seen{$_} == $max_seen_count } keys %seen; my $mode = @modes == 1 ? $modes[0] : "(" . join(", ", @modes) . ")"; $mode .= ' @ ' . $max_seen_count; my $median; my $mid = int @values/2; if (@values % 2) { $median = $values[ $mid ]; } else { $median = ($values[$mid-1] + $values[$mid])/2; } my $min = min @values; my $max = max @values; printf "n is %d, min is %g, max is %d\n", $n, $min, $max; printf "mode is %s, median is %g, mean is %g, stdev is %g\n", $mode, $median, $mean, $stdev; 

C’è anche simple-r, che può fare quasi tutto ciò che R può, ma con meno battute:

https://code.google.com/p/simple-r/

Per calcolare le statistiche descrittive di base, è necessario digitare una delle seguenti:

 r summary file.txt r summary - < file.txt cat file.txt | r summary - 

Per ciascuna deviazione media, mediana, min, max e std, il codice sarebbe:

 seq 1 100 | r mean - seq 1 100 | r median - seq 1 100 | r min - seq 1 100 | r max - seq 1 100 | r sd - 

Non diventa semplice-R!

Ancora un altro strumento: https://www.gnu.org/software/datamash/

 # Example: calculate the sum and mean of values 1 to 10: $ seq 10 | datamash sum 1 mean 1 55 5.5 

Potrebbe essere più comunemente confezionato (il primo strumento che ho trovato preconfezionato per nix almeno)

Usando xsv :

 $ echo '3 1 4 1 5 9 2 6 5 3 5 9' |tr ' ' '\n' > numbers-one-per-line.csv $ xsv stats -n < numbers-one-per-line.csv field,type,sum,min,max,min_length,max_length,mean,stddev 0,Integer,53,1,9,1,1,4.416666666666667,2.5644470922381863 # mode/median/cardinality not shown by default since it requires storing full file in memory: $ xsv stats -n --everything < numbers-one-per-line.csv | xsv table field type sum min max min_length max_length mean stddev median mode cardinality 0 Integer 53 1 9 1 1 4.416666666666667 2.5644470922381863 4.5 5 7 

Un altro strumento: tsv-summarize , dalle utility tsv di eBay . Min, max, media, media, deviazione standard sono tutti supportati. Destinato a set di dati di grandi dimensioni. Esempio:

 $ seq 10 | tsv-summarize --min 1 --max 1 --median 1 --stdev 1 1 10 5.5 3.0276503541 

Disclaimer: io sono l’autore.