Answers:
您可以使用R编程语言。
这是一个快速而肮脏的R脚本:
#! /usr/bin/env Rscript
d<-scan("stdin", quiet=TRUE)
cat(min(d), max(d), median(d), mean(d), sep="\n")
注意"stdin"
在scan
这是一种特殊的文件名从标准输入来读取(从管道或重定向装置)。
现在,您可以通过stdin将数据重定向到R脚本:
$ cat datafile
1
2
4
$ ./mmmm.r < datafile
1
4
2
2.333333
也适用于浮点数:
$ cat datafile2
1.1
2.2
4.4
$ ./mmmm.r < datafile2
1.1
4.4
2.2
2.566667
如果您不想编写R脚本文件,则可以使用Rscript
以下命令在命令行中调用真正的单行代码(仅换行以提高可读性):
$ Rscript -e 'd<-scan("stdin", quiet=TRUE)' \
-e 'cat(min(d), max(d), median(d), mean(d), sep="\n")' < datafile
1
4
2
2.333333
阅读http://cran.r-project.org/manuals.html上的 R手册。
不幸的是,完整的参考仅在PDF中可用。阅读参考的另一种方法是通过键入?topicname
交互式R会话的提示。
为了完整起见:有一个R命令,它输出所有您想要的值以及更多。不幸的是,它是一种人类友好的格式,很难以编程方式进行解析。
> summary(c(1,2,4))
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.000 1.500 2.000 2.333 3.000 4.000
r-base
。
R
语言显然是在这种情况下最适合我的需求。.根据Gilles的回答,Rscript
脚本文件的接口是最合适的(相R
对于交互式接口),并且终端中的R使得计算器很方便或测试环境(如python :)
cat datafile | Rscript -e 'print(summary(scan("stdin")));'
我实际上保留了一些awk程序,以给出单列数值数据(包括负数)的总和,数据计数,最小数据,最大数据,均值和中位数:
#!/bin/sh
sort -n | awk '
BEGIN {
c = 0;
sum = 0;
}
$1 ~ /^(\-)?[0-9]*(\.[0-9]*)?$/ {
a[c++] = $1;
sum += $1;
}
END {
ave = sum / c;
if( (c % 2) == 1 ) {
median = a[ int(c/2) ];
} else {
median = ( a[c/2] + a[c/2-1] ) / 2;
}
OFS="\t";
print sum, c, ave, median, a[0], a[c-1];
}
'
上面的脚本从stdin读取,并在一行中打印制表符分隔的输出列。
NR==1
可以继续使用(无用的-如果)以及最小/最大检查,那么所有初始化都可以在BEGIN部分中找到(好!)...也允许发表评论。.谢谢,+ 1 ...
awk
将假定“新”变量为零,因此在这种情况下该BEGIN{}
部分是不必要的。我已经解决了换行问题(也无需逃脱换行符)。我还经常OFS="\t"
清理print
线路并实施@ Peter.O的第二条评论。(是的,我的正则表达式允许.
,但按照的awk
解释0
,这是可以接受的。)
awk
脚本现在有了很大的不同。我几乎觉得您应该为上述计划功劳,才能在应得的学费中获得荣誉。
使用GNU datamash:
$ printf '1\n2\n4\n' | datamash max 1 min 1 mean 1 median 1
4 1 2.3333333333333 2
brew install datamash
如果已安装Hombrew,则为您提供macOS的工作版本。
最小值,最大值和平均值很容易通过awk获得:
% echo -e '6\n2\n4\n3\n1' | awk 'NR == 1 { max=$1; min=$1; sum=0 }
{ if ($1>max) max=$1; if ($1<min) min=$1; sum+=$1;}
END {printf "Min: %d\tMax: %d\tAverage: %f\n", min, max, sum/NR}'
Min: 1 Max: 6 Average: 3,200000
计算中位数会比较棘手,因为您需要对数字进行排序并将它们全部存储在内存中一段时间或读取两次(第一次对它们进行计数,第二次是获取中值)。这是将所有数字存储在内存中的示例:
% echo -e '6\n2\n4\n3\n1' | sort -n | awk '{arr[NR]=$1}
END { if (NR%2==1) print arr[(NR+1)/2]; else print (arr[NR/2]+arr[NR/2+1])/2}'
3
asort
而不是管道sort
,并且似乎正确地对整数和小数进行了排序。.这是我生成的版本的链接paste.ubuntu.com/612674 ...(和Kim的注释:我已经在awk上进行了几个小时的实验(使用个人兴趣的示例对我来说是更好的方法)...读者的一般注意事项:我仍然对看到其他方法感兴趣。越紧凑越好。我会等一会儿……
最低要求:
jq -s min
最大值:
jq -s max
中位数:
sort -n|awk '{a[NR]=$0}END{print(NR%2==1)?a[int(NR/2)+1]:(a[NR/2]+a[NR/2+1])/2}'
平均:
jq -s add/length
在()选项中,在jq
将每行解析为JSON或本例中的数字之后,为输入行创建一个数组。-s
--slurp
Perl一(长)线,包括中位数:
cat numbers.txt \
| perl -M'List::Util qw(sum max min)' -MPOSIX -0777 -a -ne 'printf "%-7s : %d\n"x4, "Min", min(@F), "Max", max(@F), "Average", sum(@F)/@F, "Median", sum( (sort {$a<=>$b} @F)[ int( $#F/2 ), ceil( $#F/2 ) ] )/2;'
使用的特殊选项是:
-0777
:一次读取整个文件,而不是逐行读取-a
:自动拆分为@F数组同一件事的可读性更高的脚本版本是:
#!/usr/bin/perl
use List::Util qw(sum max min);
use POSIX;
@F=<>;
printf "%-7s : %d\n" x 4,
"Min", min(@F),
"Max", max(@F),
"Average", sum(@F)/@F,
"Median", sum( (sort {$a<=>$b} @F)[ int( $#F/2 ), ceil( $#F/2 ) ] )/2;
如果你想小数,更换%d
喜欢的东西%.2f
。
只是为了在此页面上显示各种选项,这里还有另外两种方法:
1:八度
这是一个快速的八度音阶示例。
octave -q --eval 'A=1:10;
printf ("# %f\t%f\t%f\t%f\n", min(A), max(A), median(A), mean(A));'
# 1.000000 10.000000 5.500000 5.500000
2:bash +专用工具。
为了使bash处理浮点数,此脚本使用numprocess
和numaverage
来自package num-utils
。
PS。我也对进行了合理的研究bc
,但是对于这项特殊工作,它没有提供任何其他awk
功能。它是(作为“ bc”状态中的“ c”)一个计算器,这个计算器需要大量的编程,awk
并且该bash脚本...
arr=($(sort -n "LIST" |tee >(numaverage 2>/dev/null >stats.avg) ))
cnt=${#arr[@]}; ((cnt==0)) && { echo -e "0\t0\t0\t0\t0"; exit; }
mid=$((cnt/2));
if [[ ${cnt#${cnt%?}} == [02468] ]]
then med=$( echo -n "${arr[mid-1]}" |numprocess /+${arr[mid]},%2/ )
else med=${arr[mid]};
fi # count min max median average
echo -ne "$cnt\t${arr[0]}\t${arr[cnt-1]}\t$med\t"; cat stats.avg
我将第二次选择lesmana选择R,并提供我的第一个R程序。它在标准输入上每行读取一个数字,并将以空格分隔的四个数字(最小值,最大值,平均值,中位数)写入标准输出。
#!/usr/bin/env Rscript
a <- scan(file("stdin"), c(0), quiet=TRUE);
cat(min(a), max(a), mean(a), median(a), "\n");
R
就是交互式界面Rscript
,而是驱动了脚本文件,该文件可以按照您的示例进行哈希哈希处理,或从bash脚本中调用。。这些脚本可以处理命令行参数(例如stackoverflow.com/questions/2045706/…),因此看起来不错... R表达式也可以通过-e
... 在bash中使用我不知道如何R
比较bc
?
借鉴布鲁斯的代码,这是一种更有效的实现,它不会将整个数据保留在内存中。如问题中所述,它假定输入文件每行最多有一个数字。它对输入文件中包含合格编号的行进行计数,并将计数awk
与排序数据一起(位于前面)传递给命令。因此,例如,如果文件包含
6.0
4.2
8.3
9.5
1.7
那么输入awk
实际上是
5
1.7
4.2
6.0
8.3
9.5
然后,awk
脚本会在NR==1
代码块中捕获数据计数,并在看到它们时保存中间值(或两个中间值,将它们平均化以产生中位数)。
FILENAME="Salaries.csv"
(awk 'BEGIN {c=0} $1 ~ /^[-0-9]*(\.[0-9]*)?$/ {c=c+1;} END {print c;}' "$FILENAME"; \
sort -n "$FILENAME") | awk '
BEGIN {
c = 0
sum = 0
med1_loc = 0
med2_loc = 0
med1_val = 0
med2_val = 0
min = 0
max = 0
}
NR==1 {
LINES = $1
# We check whether numlines is even or odd so that we keep only
# the locations in the array where the median might be.
if (LINES%2==0) {med1_loc = LINES/2-1; med2_loc = med1_loc+1;}
if (LINES%2!=0) {med1_loc = med2_loc = (LINES-1)/2;}
}
$1 ~ /^[-0-9]*(\.[0-9]*)?$/ && NR!=1 {
# setting min value
if (c==0) {min = $1;}
# middle two values in array
if (c==med1_loc) {med1_val = $1;}
if (c==med2_loc) {med2_val = $1;}
c++
sum += $1
max = $1
}
END {
ave = sum / c
median = (med1_val + med2_val ) / 2
print "sum:" sum
print "count:" c
print "mean:" ave
print "median:" median
print "min:" min
print "max:" max
}
'
FILENAME
并知道设置的内容,但是通常,除非有充分理由不这样做,否则应始终引用shell变量,并且确保您知道自己在做什么。(4)您的答案和布鲁斯都忽略否定输入(即,以开头的数字-
);问题中没有任何迹象表明这是正确的或期望的行为。别难过 已经过去四年了,很明显,我是第一个注意到的人。
cat
并添加了解释。
这num
是一个很小的awk
包装程序,它确实可以完成更多操作,例如
$ echo "1 2 3 4 5 6 7 8 9" | num max
9
$ echo "1 2 3 4 5 6 7 8 9" | num min max median mean
..and so on
它可以避免您在超便携式awk中重新发明轮子。上面提供了文档,并在此处提供了直接链接(另请参见GitHub page)。
与perl
:
$ printf '%s\n' 1 2 4 |
perl -MList::Util=min,max -MStatistics::Basic=mean,median -w -le '
chomp(@l = <>); print for min(@l), max(@l), mean(@l), median(@l)'
1
4
2.33
2
cat/python
唯一的解决方案- 不是空输入证明!
cat data | python3 -c "import fileinput as FI,statistics as STAT; i = [int(l) for l in FI.input()]; print('min:', min(i), ' max: ', max(i), ' avg: ', STAT.mean(i), ' median: ', STAT.median(i))"
如果您对实用程序更感兴趣,而不是冷酷或聪明,那perl
是比容易的选择awk
。基本上,它将以一致的方式出现在每个* nix上,并且可以轻松,免费地在Windows上安装。我认为它的加密性还不如awk
,并且如果您希望自己编写它和R之类的内容之间有一段距离,可以使用一些统计信息模块。 )perl
脚本花了大约一分钟的时间来编写,我猜想唯一的神秘部分是while(<>)
,这是非常有用的简写,表示将通过的文件作为命令行参数,一次读取一行并放入特殊变量中的那一行$_
。因此,您可以将其放入一个名为count.pl的文件中,并以方式运行它perl count.pl myfile
。除此之外,应该很清楚地知道正在发生什么。
$max = 0;
while (<>) {
$sum = $sum + $_;
$max = $_ if ($_ > $max);
$count++;
}
$avg=$sum/$count;
print "$count numbers total=$sum max=$max mean=$avg\n";
function median()
{
declare -a nums=($(cat))
printf '%s\n' "${nums[@]}" | sort -n | tail -n $((${#nums[@]} / 2 + 1)) | head -n 1
}
sh
)作为解释器。如何将数据从文件读取到数组中也存在问题。