用于在 Linux 中打印数字统计信息的命令行实用程序
- 2024-11-12 08:36:00
- admin 原创
- 19
问题描述:
我经常发现我的文件每行只有一个数字。最后我会将其导入 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
`sedsort
awk`
解决方案 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=TRUEscan
summary`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
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件