ファイルに番号のリストが1行に1つあります。最小値、最大値、中央値および平均値を取得するにはどうすればよいですか?結果をbashスクリプトで使用したいと思います。
私の当面の状況は整数に関するものですが、浮動小数点数の解決策はすぐに役立つでしょうが、単純な整数法で十分です。
Rプログラミング言語 を使用できます。
以下は、素早く汚れたRスクリプトです。
#! /usr/bin/env Rscript
d<-scan("stdin", quiet=TRUE)
cat(min(d), max(d), median(d), mean(d), sep="\n")
scan
の"stdin"
に注意してください。これは、標準入力(つまり、パイプまたはリダイレクトから)から読み取るための特別なファイル名です。
これで、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
を使用して、コマンドラインで真の1行(読みやすいように改行のみ)を呼び出すことができます。
$ 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でのみ入手できます。参照を読み取る別の方法は、対話型Rセッションのプロンプトで?topicname
と入力することです。
完全を期すために、必要なすべての値などを出力する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
私は実際には、少し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から読み取り、タブで区切られた出力の列を1行に出力します。
GNU datamash の場合:
$ printf '1\n2\n4\n' | datamash max 1 min 1 mean 1 median 1
4 1 2.3333333333333 2
最小値、最大値、平均値は、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
数値を並べ替えてすべてをメモリにしばらく保存するか、2回読み取る必要があるため、中央値の計算は少しトリッキーです。以下は、すべての数値をメモリに保存する例です。
% 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
最小:
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
の-s
(--Slurp
)オプションは、各行をJSONまたはこの場合は数値として解析した後、入力行の配列を作成します。
pythonpy は、この種のものに適しています。
cat file.txt | py --ji -l 'min(l), max(l), numpy.median(l), numpy.mean(l)'
そして、中央値を含む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
のように置き換えます。
nums=$(<file.txt);
list=(`for n in $nums; do printf "%015.06f\n" $n; done | sort -n`);
echo min ${list[0]};
echo max ${list[${#list[*]}-1]};
echo median ${list[${#list[*]}/2]};
Simple-r が答えです。
r summary file.txt
r -e 'min(d); max(d); median(d); mean(d)' file.txt
R環境を使用して統計分析を簡素化します。
このページにさまざまなオプションを表示するために、さらに2つの方法があります。
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が浮動小数点数を処理するために、このスクリプトはパッケージnum-utils
のnumprocess
およびnumaverage
を使用します。
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
私は2番目に lesmanaのRの選択 をして、最初のRプログラムを提供します。標準入力で1行あたり1つの数値を読み取り、スペースで区切られた4つの数値(最小、最大、平均、中央値)を標準出力に書き込みます。
#!/usr/bin/env Rscript
a <- scan(file("stdin"), c(0), quiet=TRUE);
cat(min(a), max(a), mean(a), median(a), "\n");
以下のsort
/awk
タンデムがそれを行います:
sort -n | awk '{a[i++]=$0;s+=$0}END{print a[0],a[i-1],(a[int(i/2)]+a[int((i-1)/2)])/2,s/i}'
(値のカウントが偶数の場合、中央値を2つの中心値の平均として計算します)
ブルースのコードから手がかりを取り、ここにすべてのデータをメモリに保持しないより効率的な実装があります。質問で述べたように、入力ファイルには(最大で)1行に1つの番号があると想定しています。これは、修飾番号を含む入力ファイルの行をカウントし、ソートされたデータと共に(前に)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
コードブロックは、中央値(または中央値を生成するために平均化される2つの中央値)を、それらを検出したときに保存します。
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
}
'
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))"
function median()
{
declare -a nums=($(cat))
printf '%s\n' "${nums[@]}" | sort -n | tail -n $((${#nums[@]} / 2 + 1)) | head -n 1
}
クールで賢いというよりもユーティリティに関心がある場合は、Perl
の方がawk
よりも簡単です。概して、すべての* nixに一貫した動作であり、Windowsに簡単にインストールできます。私はそれもawk
よりも不可解だと思います。自分で書いたりRのようなものを書いたりする途中に家が必要な場合に使用できる統計モジュールがいくつかあります。かなりテストされていません(実際、バグがあることはわかっています)しかし、それは私の目的のために機能します)Perl
スクリプトは書くのに約1分かかりました、そして私は唯一の不可解な部分がwhile(<>)
であると思いますコマンドライン引数として渡されたファイル、一度に1行ずつ読み取り、その行を特殊変数$_
に入れます。したがって、これを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";