есть ли способ получить минимум, максимум, медиану и среднее из списка чисел в одной команде?

<p>у меня есть список номеров в файле, по одному в строке. как я могу получить минимальное, максимальное, <em>медиана</em> и <em>среднее</em> значения? я хочу использовать результаты в скрипте bash.</p><p>хотя моя непосредственная ситуация с целыми числами, решение для чисел с плавающей запятой было бы полезно в дальнейшем, но простой целочисленный метод подойдет.</p>

<p>вы можете использовать <a href="http://en.wikipedia.org/wiki/r\_%28programming\_language%29">r язык программирования</a> .</p><p>вот быстрый и грязный r-скрипт:</p><pre><code>#! /usr/bin/env rscript d<-scan("stdin", quiet=true) cat(min(d), max(d), median(d), mean(d), sep="\n") </code></pre><p>обратите внимание <code>"stdin"</code> в <code>scan</code>, которое является специальным именем файла для чтения из стандартного ввода (то есть из каналов или перенаправлений).</p><p>теперь вы можете перенаправить ваши данные через стандартный ввод в скрипт r:</p><pre><code>$ cat datafile 1 2 4 $ ./mmmm.r < datafile 1 4 2 2.333333 </code></pre><p>также работает для плавающих точек:</p><pre><code>$ cat datafile2 1.1 2.2 4.4 $ ./mmmm.r < datafile2 1.1 4.4 2.2 2.566667 </code></pre><p>если вы не хотите писать файл сценария r, вы можете вызвать настоящую однострочную строку (с переносом строки только для удобства чтения) в командной строке, используя <code>rscript</code>:</p><pre><code>$ 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 прочитайте прекрасные руководства r по адресу <a href="http://cran.r-project.org/manuals.html">http://cran.r-project.org/manuals.html .к сожалению, полная ссылка доступна только в формате 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 

на самом деле я держу небольшую программу на 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 и печатает разделенные табуляцией столбцы вывода в одну строку.

с gnu <a href="http://www.gnu.org/software/datamash/">datamash :$ printf '1\n2\n4\n' | datamash max 1 min 1 mean 1 median 1 4 1 2.3333333333333 2 </code></pre>

<p>минимальное, максимальное и среднее значения довольно легко получить с помощью awk:</p><pre><code>% 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: %dtmax: %dtaverage: %fn", min, max, sum/nr}' min: 1 max: 6 average: 3,200000 вычисление медианы немного сложнее, так как вам нужно отсортировать числа и некоторое время сохранить их в памяти или прочитать их дважды (первый раз, чтобы посчитать их, второй - чтобы получить медианное значение). вот пример, который хранит все числа в памяти:% echo -e '6n2n4n3n1' | 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 </code></pre>

<p>минимум:</p><pre class="lang-none prettyprint-override"><code>jq -s min </code></pre><p>максимум:</p><pre class="lang-none prettyprint-override"><code>jq -s max </code></pre><p>медиана:</p><pre class="lang-none prettyprint-override"><code>sort -n|awk '{a[nr]=$0}end{print(nr%2==1)?a[int(nr/2)+1]:(a[nr/2]+a[nr/2+1])/2}' средний:<pre class="lang-none prettyprint-override">jq -s add/length в jq the -s (--slurp) опция создает массив для строк ввода после разбора каждой строки как json или как числа в этом случае.

 <a href="https://github.com/russell91/pythonpy">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 : %dn"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 : %dn" 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.06fn" $n; done | sort -n`); echo min ${list[0]}; echo max ${list[${#list[]}-1]}; echo median ${list[${#list[]}/2]}; 

 <a href="https://github.com/jtprince/simpler">simple-r ответ:r summary file.txt r -e 'min(d); max(d); median(d); mean(d)' file.txt он использует среду r для упрощения статистического анализа.

просто для того, чтобы на этой странице были представлены различные варианты, вот еще два способа:1:  <a href="http://www.gnu.org/software/octave/">октава  gnu octave - это интерпретируемый язык высокого уровня, в первую очередь предназначенный для численных расчетов. он предоставляет возможности для численного решения линейных и нелинейных задач, а также для выполнения других численных экспериментов. вот быстрый пример октавы.octave -q --eval 'a=1:10; printf ("# %ft%ft%ft%fn", min(a), max(a), median(a), mean(a));' # 1.000000 10.000000 5.500000 5.500000 2:  bash + специализированные инструменты .для bash для обработки чисел с плавающей точкой этот скрипт использует numprocess и numaverage из пакета num-utils.ps. у меня также был разумный взгляд на bc, но для этой конкретной работы он не предлагает ничего кроме того, что делает awk. это (как указывает 'c' в 'bc') калькулятор - калькулятор, который требует много программирования, как awk и этот скрипт bash ...arr=($(sort -n "list" |tee >(numaverage 2>/dev/null >stats.avg) )) cnt=${#arr[@]}; ((cnt==0)) && { echo -e "0t0t0t0t0"; 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 "$cntt${arr[0]}\t${arr[cnt-1]}t$med\t"; cat stats.avg </code></pre>

<p>я буду вторым <a href="https://unix.stackexchange.com/questions/13731/is-there-a-way-to-get-the-min-max-median-and-average-of-a-list-of-numbers-in-a/13775#13775">выбор лесмана r</a> и предложу свою первую программу r. он читает одно число в строке на стандартном вводе и записывает четыре числа (мин, макс, среднее, медиана), разделенных пробелами, в стандартный вывод.</p><pre><code>#!/usr/bin/env rscript a <- scan(file("stdin"), c(0), quiet=true); cat(min(a), max(a), mean(a), median(a), "\n"); </code></pre>

<p> <a href="http://www.numcommand.com"><code>num</code></a> - это крошечная оболочка <code>awk</code>, которая точно делает это и даже больше, например,.</p><pre><code>$ 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 </code></pre><p>это спасает вас от изобретения колеса в ультрапортативном awk. документы приведены выше, и прямая ссылка <a href="https://raw.githubusercontent.com/numcommand/num/master/implementations/num-awk/num">здесь</a> (проверьте также <a href="https://github.com/numcommand/num">страница github</a> ).</p>

<p>следующий тандем <code>sort</code>/<code>awk</code> делает это:</p><pre><code>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}' </code></pre><p>(он рассчитывает медиану как среднее из двух центральных значений, если количество значений четное)</p>

<p>если взять реплики из кода брюса, то здесь есть более эффективная реализация, которая не хранит все данные в памяти. как указано в вопросе, предполагается, что входной файл имеет (самое большее) одно число в строке. он подсчитывает строки во входном файле, которые содержат квалифицирующий номер, и передает их команде <code>awk</code> вместе с (предшествующими) отсортированным данным. так, например, если файл содержит</p><pre><code>6.0 4.2 8.3 9.5 1.7 </code></pre><p>тогда входные данные для <code>awk</code> на самом деле</p><pre><code>5 1.7 4.2 6.0 8.3 9.5 </code></pre><p>затем скрипт <code>awk</code> фиксирует количество данных в <code>nr==1</code> кодирует блок и сохраняет среднее значение (или два средних значения, которые усредняются для получения медианы), когда он их видит.</p><pre><code>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 } ' </code></pre>

<p>с <code>perl</code>:</p><pre><code>$ printf '%sn' 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 заняло около минуты, и я предполагаю, что единственной загадочной частью будет while(<>), что является очень полезным сокращением, то есть take файл (ы) передаются в качестве аргументов командной строки, одновременно считывают строку и помещают эту строку в специальную переменную $\_</code>. таким образом, вы можете поместить это в файл с именем count.pl и запустить его как <code>perl count.pl myfile</code>. кроме того, должно быть до боли очевидно, что происходит.</p><pre><code>$max = 0; while (<>) { $sum = $sum + $\_; $max = $\_ if ($_ > $max); $count++; } $avg=$sum/$count; print "$count numbers total=$sum max=$max mean=$avg\n"; </code></pre>