回答:
Rプログラミング言語を使用できます。
以下に、すばやくて汚いRスクリプトを示します。
#! /usr/bin/env Rscript
d<-scan("stdin", quiet=TRUE)
cat(min(d), max(d), median(d), mean(d), sep="\n")
は、標準入力(つまり、パイプまたはリダイレクト)から読み取る特別なファイル名"stdin"
でscan
あることに注意してください。
これで、データを標準入力経由で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
、インタラクティブなインターフェイスです)。 、またはテスト環境(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];
}
'
上記のスクリプトは標準入力から読み取り、タブで区切られた出力の列を1行に出力します。
NR==1
行くことができることを意味しますif)最小/最大チェックとともに、すべての初期化はBEGINセクションに配置できます(良い!)...コメントを許可するのもいい感じです。.ありがとう、+ 1 ...
awk
は、「新しい」変数がゼロであると想定されるため、この場合、このBEGIN{}
セクションは不要です。折り返しを修正しました(改行をエスケープする必要もありません)。またOFS="\t"
、このprint
行を整理して、@ Peter.Oの2番目のコメントを実装しました。(はい、私の正規表現ができます.
が、とは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
中央値の計算はもう少し難しいです。数字を並べ替えてしばらくメモリに保存するか、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
asort
パイプではなくawkを使用しましたsort
、それは整数と小数を正しくソートしているようです。ここに私の結果のバージョンへのリンクがありますpaste.ubuntu.com/612674 ... 。個人的な興味のある例で作業することは私にとってより良い方法です)...読者への一般的なメモ:私はまだ他の方法を見ることに興味があります。よりコンパクトに、より良いです。しばらくお待ちください
pythonpyは次のようなものに適しています:
cat file.txt | py --ji -l 'min(l), max(l), numpy.median(l), numpy.mean(l)'
最小:
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
()オプションJSONとして各行を解析した後、入力ラインの配列を作成し、又はこの場合の数値として。jq
-s
--slurp
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]};
echo file.txt
多分cat
そして、中央値を含むPerlの1つの(長い)ライナー:
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
。
このページにさまざまなオプションを表示するために、さらに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が浮動小数点数を処理するために、このスクリプトはpackageからnumprocess
およびnumaverage
を使用します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
レスマナのRの選択を 2回目にし、最初のRプログラムを提供します。標準入力の行ごとに1つの数値を読み取り、スペースで区切られた4つの数値(最小、最大、平均、中央値)を標準出力に書き込みます。
#!/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/…)を処理できるため、見栄えがよくなります。また、-e
...を介してR式をbashで使用できます。私はどのように思うかR
を比較しbc
...
Bruceのコードからヒントを得て、ここにデータ全体をメモリに保持しないより効率的な実装を示します。質問で述べたように、入力ファイルには(最大で)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
}
'
FILENAME
、何に設定するかを知っているため、コードは安全ですが、一般的に、正当な理由がない限り、シェル変数を常に引用する必要があります。あなたが何をしているかを知っていることを確認してください。(4)あなたの答えとブルースの負の入力(つまり、で始まる数字-
)は無視されます。これが正しいまたは望ましい動作であることを示唆する質問には何もありません。気分を悪くしないでください。それは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ページも確認してください)。
で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
スクリプトの記述には約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";
function median()
{
declare -a nums=($(cat))
printf '%s\n' "${nums[@]}" | sort -n | tail -n $((${#nums[@]} / 2 + 1)) | head -n 1
}
sh
インタプリタとしてBash(ではなく)を使用していると言う必要があります。また、ファイルからデータを配列に読み込む方法にも問題があります。