命令行实用程序打印 Linux 中的数字统计信息

我经常发现自己有一个每行只有一个数字的文件。最后,我把它导入到 excel 中,以查看中位数、标准差等等。

Linux 中是否有命令行实用程序可以做同样的事情?我通常需要找到平均值,中位数,最小值,最大值和标准差。

57717 次浏览

至于平均数、中位数及标准差,你可以使用 awk。这通常比 R解决方案快。例如,下面将打印平均值:

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

(NR是表示记录数的 awk变量,$1表示该行的第一个(空格分隔的)参数($0将是整行,在这里也可以使用,但原则上不太安全,尽管在计算中它可能只是采用第一个参数) ,END表示在处理完整个文件后执行以下命令(也可以在 BEGIN{a=0}语句中将 a初始化为 0)。

下面是一个简单的 awk脚本,它提供了更详细的统计信息(以 CSV 文件作为输入,否则更改 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
}

在这个脚本中添加 min/max 非常简单,但是管道 sort & head/tail也同样简单:

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

是的,它叫做 perl
这里有一句简明扼要的俏皮话:

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";'

例子

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

还有命令

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
#!/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
# tchrist@perl.com


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;

意思是:

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

中位数:

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

模式:

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

这种模式计算需要偶数个样本,但是您可以看到它是如何工作的..。

标准差

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

对于这样的文件,这对 R 来说是小菜一碟:

1
2
3
4
5
6
7
8
9
10

用这个:

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

为了得到这个:

       V1
Min.   : 1.00
1st Qu.: 3.25
Median : 5.50
Mean   : 5.50
3rd Qu.: 7.75
Max.   :10.00
[1] 3.02765
  • -q标志压制 R 的启动许可和帮助输出
  • -e标志告诉 R 您将从终端传递一个表达式
  • x是一个 data.frame-基本上是一个表。它是一个能容纳多个向量/数据列的结构,如果你只是在一个向量中阅读,这就有点奇怪了。这会影响您可以使用哪些函数。
  • 有些函数,比如 summary(),自然地适应 data.frames。如果 x有多个字段,则 summary()将为每个字段提供上述描述性统计信息。
  • 但是 sd()一次只能获取一个向量,这就是为什么我为该命令索引 x(x[ , 1]返回 x的第一列)。您可以使用 apply(x, MARGIN = 2, FUN = sd)获取所有列的 SD。

为了以防万一,还有 datastat,一个用于 Linux 计算的简单程序,通过命令行进行简单的统计,

cat file.dat | datastat

将为 file.dat 的每一列输出所有行的平均值。如果你需要知道标准差、最小值、最大值,你可以分别添加 --dev--min--max选项。

datastat可以根据一个或多个“键”列的值聚合行,

cat file.dat | datastat -k 1

对于在第一列(“键”)上找到的每个不同值,将生成在键上具有相同值的所有行之间聚合的所有其他列值的平均值。您可以使用更多的列作为键字段(例如,-k1-3、-k2、4等等)。.).

它是用 C + + 编写的,运行速度快,占用内存小,可以很好地与其他工具,如 cutgrepsedsortawk等管道。

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

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

或者:

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

(免责声明: 我写了这个工具:)

还有 simple-r,它几乎可以完成 R 所能完成的任何事情,只是敲击次数更少:

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

要计算基本描述统计学,你必须输入以下内容:

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

对于每个平均值、中位数、最小值、最大值和标准偏差,代码应该是:

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 -

一点都不简单!

data_hacks是用于基本统计的 Python 命令行实用程序。

该页面的第一个例子产生了预期的结果:

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

您也可以考虑使用 克里斯托弗。它是一个高度可配置的命令行接口工具,用于计算分隔输入数字流的统计信息。

I/O 选项

  • 输入数据可以来自文件、标准输入或管道
  • 输出可以写入文件、标准输出或管道
  • 输出使用以“ #”开头的标头来启用到 gnuplot 的管道

解析选项

  • 基于信号、文件结束或空行的检测以停止处理
  • 可以设置注释和分隔符字符
  • 可以从处理中筛选出列
  • 可以根据数值约束从处理中筛选出行
  • 可以根据字符串约束从处理中筛选出行
  • 可以跳过初始标题行
  • 可以处理固定数量的行
  • 可以忽略重复的分隔符
  • 可以将行重新设置为列
  • 严格执行只处理相同大小的行
  • 包含列标题的行可用于标题输出统计信息

统计选项

  • 统计摘要(计数、最小、平均、最大、标准差)
  • 协方差
  • 相关性
  • 最小二乘偏移量
  • 最小二乘斜率
  • 直方图
  • 过滤后的原始数据

注意: 我是作者。

另一个可以用来在 ASCII 模式下计算统计和视图分布的工具是 牧师。这是一个来自 FreeBSD 的工具,但是它也为流行的 Linux 发行版打包,比如 Debian/Ubuntu。或者你可以简单地从 消息来源下载并构建它-它只需要一个 C 编译器和 C 标准库。

用法例子:

$ 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

还有一个工具: 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

可能更常用的是打包(至少是我发现的第一个针对 nix 的预打包工具)

我发现自己想在 shell 管道中完成这项工作,并花了一段时间才得到 R 的所有正确参数。这是我想到的:

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

--slave选项 “让 R 尽可能安静地运行... ... 这意味着——安静且——不保存。” -e选项告诉 R 将以下字符串视为 R 代码。第一个语句从 standard in 中读取,并将读取的内容存储在名为“ x”的变量中。scan函数的 quiet=TRUE选项禁止写入说明读取了多少项的行。第二个语句将 summary函数应用于生成输出的 x

另一个工具: 总结一下,来自 EBay 的 TSV 公用事业,支持最小、最大、平均值、中值、标准差,适用于大型数据集,例如:

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

免责声明: 我是作者。

使用 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

另外,自编写 统计数据(与“ scut”捆绑在一起)的 perl util 也可以做到这一点。美联储对 STDIN 提供了一系列数据,它试图拒绝非数据,并排放以下气体:

$ ls -lR | scut -f=4 | stats
Sum       3.10271e+07
Number    452
Mean      68643.9
Median    4469.5
Mode      4096
NModes    6
Min       2
Max       1.01171e+07
Range     1.01171e+07
Variance  3.03828e+11
Std_Dev   551206
SEM       25926.6
95% Conf  17827.9 to 119460
(for a normal distribution - see skew)
Skew      15.4631
(skew = 0 for a symmetric dist)
Std_Skew  134.212
Kurtosis  258.477
(K=3 for a normal dist)

它还可以在输入流上执行许多转换,并且如果您要求,它只发出未修饰的值; 即“ stats —— mean”将以未标记的浮点数返回平均值。