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

Posted

技术标签:

【中文标题】命令行实用程序,用于打印 linux 中的数字统计信息【英文标题】:command line utility to print statistics of numbers in linux 【发布时间】:2012-04-05 02:20:18 【问题描述】:

我经常发现自己的文件每行有一个数字。我最终将其导入 excel 以查看中位数、标准差等内容。

在 linux 中有没有命令行工具可以做同样的事情?我通常需要找到平均值、中位数、最小值、最大值和标准偏差。

【问题讨论】:

这可能是相关的:***.com/questions/214363/…. 投票结束作为工具记录。 stats.stackexchange.com/questions/24934/… || serverfault.com/questions/548322/… unix.stackexchange.com/questions/13731/… 回答这个问题的人可能也对jp, a CLI utility for making plots感兴趣。 unix.stackexchange.com/a/202889/44236 【参考方案1】:

这对 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 你将从终端传递一个表达式 xdata.frame - 基本上是一张桌子。它是一种可以容纳多个向量/数据列的结构,如果您只是读取单个向量,这有点奇怪。这会影响您可以使用哪些功能。 一些函数,比如summary(),自然会适应data.frames。如果x 有多个字段,summary() 将为每个字段提供上述描述性统计信息。 但是sd() 一次只能取一个向量,这就是我为该命令索引x 的原因(x[ , 1] 返回x 的第一列)。您可以使用 apply(x, MARGIN = 2, FUN = sd) 获取所有列的 SD。

【讨论】:

谢谢。从那以后我开始使用 R,我认为它是理解数据的好工具 节省额外搜索如何在 Ubuntu 上获取 R:sudo apt-get install r-base R 将来可能会更好地使用更多,但我猜这是一个巨大的库安装,所以我想安装下面的st 表单。与该评论无关,但我的brew install R 在 MacBook Pro Mid 2015 10.12.5 2.5GHz i7 16GB 上使用 Chrome、Atom 和其他应用程序打开了大约一个小时。其中大部分用于使用 Xcode CLT O_o 构建一些 gcc jit 补丁,但现在我很高兴使用这个答案的一部分:) 这是general data-wrangling with bash tools 上的一篇博文,发现此问题的人可能会感兴趣。【参考方案2】:

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

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

【讨论】:

关于新手安装的任何信息 如果您使用自制软件安装,这就像brew install st 一样简单。 注意st 也可能引用simple terminal【参考方案3】:

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

awk 'a+=$1 ENDprint a/NR' myfile

(NR 是记录数的awk 变量,$1 表示该行的第一个(空格分隔)参数($0 将是整行,这也可以在这里工作,但是原则上会不太安全,尽管对于计算它可能只需要第一个参数)和END 意味着在处理完整个文件后将执行以下命令(也可以将a 初始化为@ 987654330@ 在BEGINa=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

在这个脚本中添加最小值/最大值很简单,但通过管道传递sorthead/tail 一样容易:

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

【讨论】:

【参考方案4】:

另一个可用于以 ASCII 模式计算统计数据和视图分布的工具是 ministat。它是来自 FreeBSD 的工具,但它也被打包用于流行的 Linux 发行版,如 Debian/Ubuntu。或者您可以简单地从 sources 下载并构建它 - 它只需要 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

【讨论】:

【参考方案5】:

是的,它叫做 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

【讨论】:

我确信这行得通,但是只做一行会让我的眼睛流血。为什么不创建一个脚本,而不是那种暴行? 我很确定“函数式语言”!=“尽可能简洁地将所有内容写在一行上”。 仅仅因为你可以做某事一行并不意味着你应该。 Oneliners 绝对不是用来阅读的。但是他们很高兴只是复制粘贴到我的腻子中,并从 apache 日志中获取一些数字的统计信息......所以 bua roxx 命令行(至少是 bash)也支持多行字符串。只需在文字中使用换行符即可。【参考方案6】:

另一个工具: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 预打包的工具)

【讨论】:

【参考方案7】:

平均值:

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

【讨论】:

做得很好 - 并且使用了每个 Linux 发行版上的工具。 @rbellamy - 谢谢!不仅仅是 Linux - 我管理着 FreeBSD 系统,awkgawk 之间的区别很重要(因为 BSD 上的 Plain Old Awk 不包括 asort())。【参考方案8】:

以防万一,有datastat,这是一个简单的程序,用于从命令行计算简单统计信息的 Linux。例如,

cat file.dat | datastat

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

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

cat file.dat | datastat -k 1

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

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

【讨论】:

useless use of cat 的文体轻微畏缩 我认为缺少作者身份免责声明。【参考方案9】:

data_hacks is a Python command-line utility for basic statistics.

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

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

【讨论】:

【参考方案10】:

您也可以考虑使用clistats。它是一个高度可配置的命令行界面工具,用于计算分隔输入数字流的统计信息。

I/O 选项

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

解析选项

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

统计选项

汇总统计信息(计数、最小值、平均值、最大值、标准差) 协方差 相关性 最小二乘偏移 最小二乘斜率 直方图 过滤后的原始数据

注意:我是作者。

【讨论】:

【参考方案11】:

我发现自己想在 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 选项 "Make(s) R run as quietly as possible...It implies --quiet and --no-save." -e 选项告诉 R 将以下字符串视为 R 代码。第一条语句从标准输入中读取,并将读取的内容存储在名为“x”的变量中。 scan 函数的 quiet=TRUE 选项禁止写入一行,说明读取了多少项目。第二条语句将summary 函数应用于x,从而产生输出。

【讨论】:

【参考方案12】:

还有 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 -

没有得到任何简单的-R!

【讨论】:

有趣的是,它是 R 的 Perl 包装器。R 不是编程语言! >:-)【参考方案13】:
#!/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;

【讨论】:

【参考方案14】:

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

【讨论】:

使用brew 安装它揭示了很多依赖关系。这个功能相当“重”。 所以不要使用brew? github.com/BurntSushi/xsv/releases 已经为 macos 预编译了二进制文件,因此没有理由安装完整的 rust 工具链或 brew 所做的任何事情。【参考方案15】:

另一个工具:tsv-summarize,来自eBay's tsv utilities。最小值、最大值、平均值、中值、标准差都支持。适用于大型数据集。示例:

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

免责声明:我是作者。

【讨论】:

【参考方案16】:

另外,自写stats,(与'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)

它还可以对输入流进行许多转换,如果你要求它,它只会发出未修饰的值; ie 'stats --mean' 会将平均值作为未标记的浮点数返回。

【讨论】:

以上是关于命令行实用程序,用于打印 linux 中的数字统计信息的主要内容,如果未能解决你的问题,请参考以下文章

Linux命令之统计文件字数字符数字节数及行数信息wc

用于向Mountain Lion中的通知中心发送通知的命令行实用程序

linux基础-统计命令:wc

linux每日命令(36):wc命令

linux常用基本命令

Linux命令之wc(Word Count)