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.
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):
-q
Supprime la licence de démarrage de R et l'aide à la sortie-e
Indique à R que vous passerez une expression du terminalx
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.summary()
, acceptent naturellement data.frames
. Si x
avait plusieurs champs, summary()
fournirait les statistiques descriptives ci-dessus pour chacun.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.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 :))
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
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
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
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
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]: *
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.
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.
REMARQUE: je suis l'auteur.
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.
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)
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!
#!/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;
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.
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