it-swarm-ko.tech

단일 명령으로 숫자 목록의 최소, 최대, 중앙값 및 평균을 얻는 방법이 있습니까?

한 줄에 하나씩 파일에 숫자 목록이 있습니다. 최소, 최대, 중간 값평균 값을 어떻게 얻을 수 있습니까? bash 스크립트에서 결과를 사용하고 싶습니다.

필자의 즉각적인 상황은 정수이지만 부동 소수점 숫자에 대한 솔루션은 선 아래에 유용하지만 간단한 정수 방법이 좋습니다.

101
Peter.O

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를 사용하여 명령 행에서 실제 단일 라이너 (가독성을 위해서만 줄 바꿈)를 호출 할 수 있습니다.

$ 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 
54
lesmana

실제로 작은 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에서 읽고 탭으로 구분 된 출력 열을 한 줄에 인쇄합니다.

55
Bruce Ediger

GNU datamash 포함) :

$ printf '1\n2\n4\n' | datamash max 1 min 1 mean 1 median 1
4   1   2.3333333333333 2
53
cuonglm

최소, 최대 및 평균은 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
20
gelraen

최저한의:

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 또는이 경우 숫자로 구문 분석 한 후 입력 행에 대한 배열을 작성합니다.

20
nisetama

pythonpy 이런 종류의 일에는 잘 작동합니다.

cat file.txt | py --ji -l 'min(l), max(l), numpy.median(l), numpy.mean(l)'
18
RussellStewart

그리고 중앙값을 포함한 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.

7
mivk
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]};
7
NotANumber

Simple-r 이 답입니다 :

r summary file.txt
r -e 'min(d); max(d); median(d); mean(d)' file.txt

R 환경을 사용하여 통계 분석을 단순화합니다.

6
user48270

이 페이지에 제시된 다양한 옵션을 위해 두 가지 방법이 더 있습니다.

1 : 옥타브

  • GNU Octave는 주로 수치 계산을위한 고급 해석 언어입니다. 선형 및 비선형 문제의 수치 솔루션과 다른 수치 실험을 수행하는 기능을 제공합니다.

다음은 빠른 옥타브 예제입니다.

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에서 numprocessnumaverage를 사용합니다.

추신. 나는 또한 bc를 합리적으로 보았지만,이 특정 직업에 대해서는 awk가하는 것 이상의 것을 제공하지 않습니다. awk와 같은 bash 스크립트와 같은 프로그래밍이 필요한 계산기입니다 ( 'bc'상태의 'c').


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 
5
Peter.O

두 번째 lesmana의 R 선택 하고 첫 번째 R 프로그램을 제공하겠습니다. 표준 입력에서 한 줄에 하나의 숫자를 읽고 공백으로 구분 된 4 개의 숫자 (최소, 최대, 평균, 중앙값)를 표준 출력에 씁니다.

#!/usr/bin/env Rscript
a <- scan(file("stdin"), c(0), quiet=TRUE);
cat(min(a), max(a), mean(a), median(a), "\n");

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 페이지 도 확인하십시오).

3
coderofsalvation

아래의 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
mik

Bruce의 코드에서 힌트를 얻은 다음은 전체 데이터를 메모리에 보관하지 않는보다 효율적인 구현입니다. 질문에서 언급했듯이 입력 파일에는 줄당 하나의 숫자가 있다고 가정합니다. 규정 된 숫자를 포함하는 입력 파일의 행을 계산하고 정렬 된 데이터와 함께 (앞에) 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
  }
'
2
Rahul Agarwal

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
2
Stéphane Chazelas

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))"
1
ravwojdyla
function median()
{
    declare -a nums=($(cat))
    printf '%s\n' "${nums[@]}" | sort -n | tail -n $((${#nums[@]} / 2 + 1)) | head -n 1
}  
0
David McLaughlin

시원하거나 영리하지 않고 유틸리티에 더 관심이 있다면 Perlawk보다 쉬운 선택입니다. 전반적으로 일관된 동작으로 모든 * nix에 있으며, Windows에 쉽고 무료로 설치할 수 있습니다. 나는 또한 awk보다 덜 비밀스럽고, 직접 작성하는 것과 R과 같은 것 사이의 중간 집을 원한다면 사용할 수있는 통계 모듈이있을 것입니다. 그러나 그것은 내 목적을 위해 작동합니다) Perl 스크립트를 작성하는 데 약 1 분이 걸렸으며 유일한 암호 부분은 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";
0
iain