web-dev-qa-db-fra.com

utilitaire de ligne de commande pour imprimer des statistiques de nombres sous linux

Je me retrouve souvent avec un fichier qui a un numéro par ligne. Je finis par l'importer dans Excel pour voir des choses comme la médiane, l'écart-type, etc.

Existe-t-il un utilitaire de ligne de commande sous Linux pour faire de même? J'ai généralement besoin de trouver l'écart moyen, médian, min, max et std.

61
MK.

C'est un jeu d'enfant avec R. Pour un fichier qui ressemble à ceci:

1
2
3
4
5
6
7
8
9
10

Utilisez ceci:

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

Pour l'obtenir:

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

Modifier pour ajouter quelques commentaires de clarification (parce que j'y suis revenu et que je ne me souvenais pas de certaines des raisons):

  • Le drapeau -q Supprime la licence de démarrage de R et l'aide à la sortie
  • Le drapeau -e Indique à R que vous passerez une expression du terminal
  • x est un data.frame - une table, en gros. C'est une structure qui accueille plusieurs vecteurs/colonnes de données, ce qui est un peu particulier si vous ne faites que lire dans un seul vecteur. Cela a un impact sur les fonctions que vous pouvez utiliser.
  • Certaines fonctions, comme summary(), acceptent naturellement data.frames. Si x avait plusieurs champs, summary() fournirait les statistiques descriptives ci-dessus pour chacun.
  • Mais sd() ne peut prendre qu'un seul vecteur à la fois, c'est pourquoi j'indexe x pour cette commande (x[ , 1] Renvoie la première colonne de x) . Vous pouvez utiliser apply(x, MARGIN = 2, FUN = sd) pour obtenir les SD de toutes les colonnes.
52
Matt Parker

Utilisation de "st" ( https://github.com/nferraz/st )

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

Ou:

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

(AVERTISSEMENT: j'ai écrit cet outil :))

37
user2747481

Pour la moyenne, la médiane et l'écart type, vous pouvez utiliser awk. Ce sera généralement plus rapide que les solutions R. Par exemple, ce qui suit imprimera la moyenne:

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

(NR est une variable awk pour le nombre d'enregistrements, $1 signifie le premier argument (séparé par des espaces) de la ligne ($0 serait la ligne entière, ce qui fonctionnerait également ici mais en principe serait moins sécurisé, bien que pour le calcul, il faudrait probablement de toute façon le premier argument) et END signifie que les commandes suivantes seront exécutées après avoir traité l'intégralité du fichier (on aurait aussi pu initialiser a en 0 dans un BEGIN{a=0} instruction)).

Voici un simple script awk qui fournit des statistiques plus détaillées (prend un fichier CSV en entrée, sinon changez FS):

#!/usr/bin/awk -f

BEGIN {
    FS=",";
}
{
   a += $1;
   b[++i] = $1;
}
END {
    m = a/NR; # mean
    for (i in b)
    {
        d += (b[i]-m)^2;
        e += (b[i]-m)^3;
        f += (b[i]-m)^4;
    }
    va = d/NR; # variance
    sd = sqrt(va); # standard deviation
    sk = (e/NR)/sd^3; # skewness
    ku = (f/NR)/sd^4-3; # standardized kurtosis
    print "N,sum,mean,variance,std,SEM,skewness,kurtosis"
    print NR "," a "," m "," va "," sd "," sd/sqrt(NR) "," sk "," ku
}

Il est simple d'ajouter min/max à ce script, mais il est aussi facile de diriger sort & head/tail:

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

Y.a. outil qui pourrait être utilisé pour calculer des statistiques et afficher la distribution en ASCII est ministat. C'est un outil de FreeBSD, mais il est également empaqueté pour une distribution Linux populaire comme Debian/Ubuntu.

Exemple d'utilisation:

$ 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 <stdin>
+--------------------------------------------------------------------------+
| x                                                                        |
|xx                                   xx    x x                           x|
|   |__________________________A_______M_________________|                 |
+--------------------------------------------------------------------------+
    N           Min           Max        Median           Avg        Stddev
x   8      7.388075      7.692373       7.54768     7.5118156    0.11126122
19
Aliaksei Ramanau

Oui, ça s'appelle Perl
et voici une ligne simple concise:

Perl -e 'use List::Util qw(max min sum); @a=();while(<>){$sqsum+=$_*$_; Push(@a,$_)}; $n=@a;$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";'

Exemple

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

Et la commande

cat tt | Perl -e 'use List::Util qw(max min sum); @a=();while(<>){$sqsum+=$_*$_; Push(@a,$_)}; $n=@a;$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
15
bua

Moyenne:

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

médiane:

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

Mode:

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

Ce calcul de mode nécessite un nombre pair d'échantillons, mais vous voyez comment cela fonctionne ...

Écart type:

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

data_hacks est un Python utilitaire de ligne de commande pour les statistiques de base.

Le premier exemple de cette page produit les résultats souhaités:

$ 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]: *
8
Matt Parker

Juste au cas où, il y a datastat , un programme simple pour Linux calculant des statistiques simples à partir de la ligne de commande. Par exemple,

cat file.dat | datastat

affichera la valeur moyenne sur toutes les lignes pour chaque colonne de file.dat. Si vous avez besoin de connaître l'écart type, min, max, vous pouvez ajouter le --dev, --min et --max options, respectivement.

datastat a la possibilité d'agréger des lignes en fonction de la valeur d'une ou plusieurs colonnes "clés". Par exemple,

cat file.dat | datastat -k 1

produira, pour chaque valeur différente trouvée sur la première colonne (la "clé"), la moyenne de toutes les autres valeurs de colonne comme agrégées parmi toutes les lignes avec la même valeur sur la clé. Vous pouvez utiliser plus de colonnes comme champs clés (par exemple, -k 1-3, -k 2,4 etc ...).

Il est écrit en C++, s'exécute rapidement et avec peu d'occupation de mémoire, et peut être joliment canalisé avec d'autres outils tels que cut, grep, sed, sort , awk etc.

7
Tommaso

Vous pouvez également envisager d'utiliser clistats . Il s'agit d'un outil d'interface de ligne de commande hautement configurable pour calculer les statistiques d'un flux de nombres d'entrée délimités.

Options d'E/S

  • Les données d'entrée peuvent provenir d'un fichier, d'une entrée standard ou d'un tuyau
  • La sortie peut être écrite dans un fichier, une sortie standard ou un tube
  • La sortie utilise des en-têtes qui commencent par "#" pour permettre à la tuyauterie de gnuplot

Options d'analyse

  • Détection de signal, de fin de fichier ou de ligne vierge pour arrêter le traitement
  • Le caractère de commentaire et de délimiteur peut être défini
  • Les colonnes peuvent être filtrées du traitement
  • Les lignes peuvent être filtrées du traitement en fonction de la contrainte numérique
  • Les lignes peuvent être filtrées du traitement en fonction de la contrainte de chaîne
  • Les lignes d'en-tête initiales peuvent être ignorées
  • Un nombre fixe de lignes peut être traité
  • Les délimiteurs en double peuvent être ignorés
  • Les lignes peuvent être remodelées en colonnes
  • Appliquer strictement que seules les lignes de même taille sont traitées
  • Une ligne contenant les titres des colonnes peut être utilisée pour titrer les statistiques de sortie

Options statistiques

  • Statistiques récapitulatives (nombre, minimum, moyenne, maximum, écart type)
  • Covariance
  • Corrélation
  • Décalage des moindres carrés
  • Pente des moindres carrés
  • Histogramme
  • Données brutes après filtrage

REMARQUE: je suis l'auteur.

7
dpmcmlxxvi

Je me suis retrouvé à vouloir le faire dans un pipeline Shell, et obtenir tous les bons arguments pour R a pris du temps. Voici ce que j'ai trouvé:

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'option --slave"Make (s) R s'exécute aussi silencieusement que possible ... Cela implique --quiet et --no-save." L'option -e indique à R de traiter la chaîne suivante comme du code R. La première instruction lit à partir de la norme dans et stocke ce qui est lu dans la variable appelée "x". L'option quiet=TRUE De la fonction scan supprime l'écriture d'une ligne indiquant le nombre d'éléments lus. La deuxième instruction applique la fonction summary à x, qui produit la sortie.

6
Jose Quinteiro

Encore un autre outil: 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

Pourrait être plus souvent emballé (le premier outil que j'ai trouvé préemballé pour nix au moins)

5
olejorgenb

Il y a aussi simple-r, qui peut faire presque tout ce que R peut faire, mais avec moins de touches:

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

Pour calculer les statistiques descriptives de base, il faudrait taper l'un des éléments suivants:

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

Pour chacun des écarts moyen, médian, min, max et std, le code serait:

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 -

N'obtient pas de simple-R!

3
Tom
#!/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 "N.N"
        (?:
            (?: [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;
3
tchrist

Un autre outil: tsv-summarize, de tilitaires tsv d'eBay . Min, max, moyenne, médiane, écart-type sont tous pris en charge. Destiné aux grands ensembles de données. Exemple:

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

Avertissement: je suis l'auteur.

2
JonDeg

En utilisant 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
1
unhammer