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

2024-11-12 08:36:00
admin
原创
20
摘要:问题描述:我经常发现我的文件每行只有一个数字。最后我会将其导入 Excel 中来查看中位数、标准差等信息。Linux 中是否有命令行实用程序可以执行相同操作?我通常需要查找平均值、中位数、最小值、最大值和标准差。解决方案 1:使用 R 可以轻松完成此操作。对于如下所示的文件:1 2 3 4 5 6 7 8 9...

问题描述:

我经常发现我的文件每行只有一个数字。最后我会将其导入 Excel 中来查看中位数、标准差等信息。

Linux 中是否有命令行实用程序可以执行相同操作?我通常需要查找平均值、中位数、最小值、最大值和标准差。


解决方案 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 你将从终端传递一个表达式

  • x基本上是一张data.frame表。它是一种可容纳多个向量/数据列的结构,如果您只读取单个向量,则这有点奇怪。这会影响您可以使用哪些函数。

  • 有些函数,例如summary(),自然地适应data.frames。如果x有多个字段,summary()将为每个字段提供上述描述性统计数据。

  • sd()一次只能取一个向量,这就是我x为该命令建立索引的原因(x[ , 1]返回第一列x)。您可以使用它apply(x, MARGIN = 2, FUN = sd)来获取所有列的 SD。

解决方案 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

(免责声明:这个工具是我编写的:))

解决方案 3:

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

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

NR是表示awk记录数的变量,$1意味着行的第一个(以空格分隔的)参数($0将是整行,这在这里也可以工作,但原则上不太安全,尽管对于计算来说它可能只会采用第一个参数)并且END意味着以下命令将在处理整个文件后执行(也可以在语句中初始化a为)。0`BEGIN{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
}

向此脚本添加最小值/最大值很简单,但使用管道sort& head/也同样简单tail :

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

解决方案 4:

另一个可用于计算统计数据并在 ASCII 模式下查看分布的工具是ministat 。它是 FreeBSD 的一个工具,但它也为 Debian/Ubuntu 等流行的 Linux 发行版打包。或者您可以简单地从源代码下载并构建它- 它只需要一个 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
sum:$s
avg:$a
std:$std
med:$medmax:$mmin:$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
sum:$s
avg:$a
std:$std
med:$medmax:$mmin:$mm";'
records:9
sum:35.5
avg:3.94444444444444
std:1.86256162380447
med:4
max:7.
min:1

解决方案 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

解决方案 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++ 编写的,运行速度快、内存占用小,并且可以与其他工具(如、、、、等cut)很好地集成。grep`sedsortawk`

解决方案 9:

我发现自己想在 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

选项“使 R 尽可能安静地运行……这意味着 --quiet 和 --no-save。”该--slave选项告诉 R 将以下字符串视为 R 代码。第一个语句从标准输入读取,并将读取的内容存储在名为“x”的变量中。该函数的选项禁止写入一行说明读取了多少项。第二个语句将函数应用于,从而产生输出。-e`quiet=TRUEscansummary`x

解决方案 10:

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

解决方案 11:

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

I/O 选项

  • 输入数据可以来自文件、标准输入或管道

  • 输出可以写入文件、标准输出或管道

  • 输出使用以“#”开头的标题来启用到 gnuplot 的管道

解析选项

  • 根据信号、文件结尾或空行检测来停止处理

  • 可以设置注释和分隔符

  • 可以从处理中过滤掉列

  • 可以根据数值约束从处理中过滤掉行

  • 可以根据字符串约束从处理中过滤掉行

  • 可以跳过初始标题行

  • 可以处理固定数量的行

  • 重复的分隔符可以被忽略

  • 行可以重新调整为列

  • 严格执行仅处理相同大小的行

  • 包含列标题的行可用于为输出统计数据添加标题

统计选项

  • 汇总统计数据(计数、最小值、平均值、最大值、标准差)

  • 协方差

  • 相关性

  • 最小二乘偏移

  • 最小二乘斜率

  • 直方图

  • 过滤后的原始数据

注:我是作者。

解决方案 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!

解决方案 13:

使用xsv:

$ echo '3 1 4 1 5 9 2 6 5 3 5 9' |tr ' ' '
' > 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

解决方案 14:

#!/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, $min, $max;
printf "mode is %s, median is %g, mean is %g, stdev is %g
", 
    $mode, $median, $mean, $stdev;

解决方案 15:

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

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

免责声明:我是作者。

解决方案 16:

此外,自写统计数据(与“scut”捆绑在一起)是一个 perl 实用程序,可以完成此操作。在 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”将返回平均值作为未标记的浮点数。

解决方案 17:

解决方案不够?-):我想加入 gnuplot stats 命令。Gnuplot 是一款速度极快的数据分析工具 - 绘图、回归...

seq 10 | gnuplot -e "stats '-' u 1"

* FILE: 
  Records:           10
  Out of range:       0
  Invalid:            0
  Header records:     0
  Blank:              0
  Data Blocks:        1

* COLUMN: 
  Mean:               5.5000
  Std Dev:            2.8723
  Sample StdDev:      3.0277
  Skewness:           0.0000
  Kurtosis:           1.7758
  Avg Dev:            2.5000
  Sum:               55.0000
  Sum Sq.:          385.0000

  Mean Err.:          0.9083
  Std Dev Err.:       0.6423
  Skewness Err.:      0.7746
  Kurtosis Err.:      1.5492

  Minimum:            1.0000 [ 0]
  Maximum:           10.0000 [ 9]
  Quartile:           3.0000 
  Median:             5.5000 
  Quartile:           8.0000 

解决方案 18:

选定的答案使用 R。使用相同的工具,我发现一个脚本比单行脚本更好用,因为它可以更舒适地进行修改以添加任何特定的统计数据,或者以不同的方式格式化输出。

鉴于此文件data.txt

1
2
3
4
5
6
7
8
9
10

将此basic-stats脚本放在$PATH

#!/usr/bin/env Rscript

# Build a numeric vector.
x <- as.numeric(readLines("stdin"))

# Custom basic statistics.
basic_stats <- data.frame(
    N = length(x), min = min(x), mean = mean(x), median = median(x), stddev = sd(x),
    percentile_95 = quantile(x, c(.95)), percentile_99 = quantile(x, c(.99)),
    max = max(x))

# Print output.
print(round(basic_stats, 3), row.names = FALSE, right = FALSE)

执行basic-stats < data.txt以将以下内容打印到标准输出:

 N  min mean median stddev percentile_95 percentile_99 max
 10 1   5.5  5.5    3.028  9.55          9.91          10 

将脚本的最后两行替换为以下内容,格式会看起来更美观一些:

# Print output. Tabular formatting is done by the `column` command.
temp_file <- tempfile("basic_stats_", fileext = ".csv")
write.csv(round(basic_stats, 3), file = temp_file, row.names = FALSE, quote = FALSE)
system(paste("column -s, -t", temp_file))
. <- file.remove(temp_file)

这是现在的输出,列之间有 2 个空格(而不是 1 个空格):

N   min  mean  median  stddev  percentile_95  percentile_99  max
10  1    5.5   5.5     3.028   9.55           9.91           10
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用