32
$\begingroup$

Is there any command-line tool that accepts the flow of numbers (in ascii format) from standard input and gives the basic descriptive statistics for this flow, such as min, max, average, median, RMS, quantiles etc? The output is welcome to be parseable by the next command in command-line chain. Working environment is Linux, but other options are welcome.

$\endgroup$
4

12 Answers 12

31
$\begingroup$

You can do this with R, which may be a bit of overkill...

EDIT 2: [OOPS, looks like someone else hit with Rscript while I was retyping this.] I found an easier way. Installed with R should be Rscript, which is meant to do what you're trying to do. For example, if I have a file bar which has a list of numbers, one per line:

Rscript -e 'summary (as.numeric (readLines ("stdin")))' < bar

Will send the numbers in the file into R and run R's summary command on the lines, returning something like:

   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   1.00    2.25    3.50    3.50    4.75    6.00 

You could also do something like:

Rscript -e 'quantile (as.numeric (readLines ("stdin")), probs=c(0.025, 0.5, 0.975))'

to get quantiles. And you could obviously chop off the first line of output (which contains labels) with something like:

Rscript -e 'summary (as.numeric (readLines ("stdin")))' < bar | tail -n +2

I'd highly recommend doing what you want in interactive R first, to make sure you have the command correct. In trying this, I left out the closing parenthesis and Rscript returns nothing -- no error message, no result, just nothing.

(For the record, file bar contains:

1
2
3
4
5
6
$\endgroup$
4
  • $\begingroup$ So, I should prepend my flow with those R commands? $\endgroup$
    – mbaitoff
    Mar 20, 2012 at 15:27
  • $\begingroup$ @mbaitoff: Yes. For my test, I created a file foo which contained the summary (as.numeric (readLines())) as its first line, then one numeric data item per line for the rest of the file. The readLines() is just reading from stdin (which is all of what follows, until the end of file). $\endgroup$
    – Wayne
    Mar 20, 2012 at 16:01
  • $\begingroup$ Looks like we seriously stuck to R in both answers, and it seems to be a huge tool for a tiny task. Well, the answers work, but anyway, is there something else except R? $\endgroup$
    – mbaitoff
    Mar 21, 2012 at 5:12
  • 2
    $\begingroup$ @mbaitoff: You could use Python with scipy, especially if you already use Python. If you use/like Clojure (lisp based on JVM, clojure.org), there's the Incanter (incanter.org) statistical environment built on that. You could also try gnu Octave. $\endgroup$
    – Wayne
    Mar 21, 2012 at 13:14
33
$\begingroup$

Try "st":

$ seq 1 10 | st
N   min   max   sum   mean  stddev
10  1     10    55    5.5   3.02765

$ seq 1 10 | st --transpose
N       10
min     1
max     10
sum     55
mean    5.5
stddev  3.02765

You can also see the five number summary:

$ seq 1 10 | st --summary
min  q1    median   q3    max
1    3.5   5.5      7.5   10

You can download it here:

https://github.com/nferraz/st

(DISCLAIMER: I wrote this tool :))

$\endgroup$
6
  • $\begingroup$ Welcome to the site, @user2747481. Would you mind fleshing this answer out a bit? We would like our answers to be mostly self-contained. Since you are new here, you may want to read our about page, which contains information for new users. $\endgroup$ Sep 5, 2013 at 15:52
  • 1
    $\begingroup$ Beware that st may also reference to simple terminal. $\endgroup$ Feb 6, 2019 at 10:21
  • 1
    $\begingroup$ This is awesome. brew installed, ran exactly as I expected it to. A++ $\endgroup$
    – Locane
    Jan 30, 2020 at 18:57
  • 1
    $\begingroup$ Nice to have something which installs with minimal dependencies, worked even from a centos-minimal image! $\endgroup$
    – lost
    Oct 9, 2020 at 11:06
  • 1
    $\begingroup$ ubuntu users can install this via apt install st-console manpages.ubuntu.com/manpages/focal/man1/st-console.1.html $\endgroup$
    – 22degrees
    Oct 21, 2022 at 17:30
12
$\begingroup$

R provides a command called Rscript. If you have only a few numbers that you can paste on the command line, use this one liner:

Rscript -e 'summary(as.numeric(commandArgs(TRUE)))' 3 4 5 9 7

which results in

Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
3.0     4.0     5.0     5.6     7.0     9.0 

If you want to read from the standard input use this:

echo 3 4 5 9 7 | Rscript -e 'summary(as.numeric(read.table(file("stdin"))))'

If number on the standard input are separated by carriage returns (ie one number per line), use

Rscript -e 'summary(as.numeric(read.table(file("stdin"))[,1]))'

One can create aliases for these commands:

alias summary='Rscript -e "summary(as.numeric(read.table(file(\"stdin\"))[,1]))"'
du -s /usr/bin/* | cut -f1 | summary
Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
0.0     8.0    20.0    93.6    44.0  6528.0
$\endgroup$
2
  • $\begingroup$ +1: Sorry I'd just found Rscript and edited my answer to include this, so we've ended up with a similar answer. Your read.table idea is a nice way to get around one-item-per-line. $\endgroup$
    – Wayne
    Mar 20, 2012 at 18:59
  • $\begingroup$ Ok, thanks for the acknowledgement and the +1. $\endgroup$
    – Arnaud A
    Mar 20, 2012 at 22:45
10
$\begingroup$

datamash is another great option. It's from the GNU Project.

If you have homebrew / linuxbrew you can do:

brew install datamash

$\endgroup$
1
  • 2
    $\begingroup$ It's amazing for calculating stats over access logs. For example cat only_times.txt | datamash --header-out mean 1 perc:50 1 perc:90 1 perc:95 1 perc:97 1 perc:99 1 perc:100 1 | column -t. $\endgroup$ Jul 29, 2021 at 11:20
6
$\begingroup$

Y.a. tool which could be used for calculating statistics and view distribution in ASCII mode is ministat. It's a tool from FreeBSD, but it also packaged for popular Linux distribution like Debian/Ubuntu.

Usage example:

$ cat test.log 
Handled 1000000 packets.Time elapsed: 7.575278
Handled 1000000 packets.Time elapsed: 7.569267
Handled 1000000 packets.Time elapsed: 7.540344
Handled 1000000 packets.Time elapsed: 7.547680
Handled 1000000 packets.Time elapsed: 7.692373
Handled 1000000 packets.Time elapsed: 7.390200
Handled 1000000 packets.Time elapsed: 7.391308
Handled 1000000 packets.Time elapsed: 7.388075

$ cat test.log| awk '{print $5}' | ministat -w 74
x <stdin>
+--------------------------------------------------------------------------+
| x                                                                        |
|xx                                   xx    x x                           x|
|   |__________________________A_______M_________________|                 |
+--------------------------------------------------------------------------+
    N           Min           Max        Median           Avg        Stddev
x   8      7.388075      7.692373       7.54768     7.5118156    0.11126122
$\endgroup$
1
  • $\begingroup$ Because simple statistics are so easy to calculate it's tempting to write an ad-hoc solution time and again. For a programmer it's a habit. I guess I've written hundreds of one-liners in octave, jq, r, shell or awk to calculate basic statistics. For me, this particular answer proved to be the most practicable solution. It's small, simple, ubiquitous and, my distro's package repository has it . Using it might actually become a habit that sticks (finally). $\endgroup$
    – wnrph
    Dec 10, 2021 at 14:00
2
$\begingroup$

There is also simple-r, which can do almost everything that R can, but with less keystrokes:

https://code.google.com/p/simple-r/

To calculate basic descriptive statistics, one would have to type one of:

r summary file.txt
r summary - < file.txt
cat file.txt | r summary -

Doesn't get any simple-R!

$\endgroup$
2
$\begingroup$

There is sta, which is a c++ varient of st, also referenced in these comments.

Being written in c++, it's fast and can handle large datasets. It's simple to use, includes the choice of unbiased or biased estimators, and can output more detailed information such as standard error.

You can download sta at github.

Disclaimer: I'm the author of sta.

$\endgroup$
1
$\begingroup$

Just in case, there's datastat

https://sourceforge.net/p/datastat/code/

a simple program for Linux computing simple statistics from the command-line. For example,

cat file.dat | datastat

will output the average value across all rows for each column of file.dat. If you need to know the standard deviation, min, max, you can add the --dev, --min and --max options, respectively.

datastat has the possibility to aggregate rows based on the value of one or more "key" columns.

It's written in C++, runs fast and with small memory occupation, and can be piped nicely with other tools such as cut, grep, sed, sort, awk, etc.

$\endgroup$
1
$\begingroup$

You might also consider using clistats. It is a highly configurable command line interface tool to compute statistics for a stream of delimited input numbers.

I/O options

  • Input data can be from a file, standard input, or a pipe
  • Output can be written to a file, standard output, or a pipe
  • Output uses headers that start with "#" to enable piping to gnuplot

Parsing options

  • Signal, end-of-file, or blank line based detection to stop processing
  • Comment and delimiter character can be set
  • Columns can be filtered out from processing
  • Rows can be filtered out from processing based on numeric constraint
  • Rows can be filtered out from processing based on string constraint
  • Initial header rows can be skipped
  • Fixed number of rows can be processed
  • Duplicate delimiters can be ignored
  • Rows can be reshaped into columns
  • Strictly enforce that only rows of the same size are processed
  • A row containing column titles can be used to title output statistics

Statistics options

  • Summary statistics (Count, Minimum, Mean, Maximum, Standard deviation)
  • Covariance
  • Correlation
  • Least squares offset
  • Least squares slope
  • Histogram
  • Raw data after filtering

NOTE: I'm the author.

$\endgroup$
1
$\begingroup$

Stumbled across this old thread looking for something else. Wanted the same thing, couldn't find anything simple, so did it in perl, fairly trivial, but use it multiple times a day: http://moo.nac.uci.edu/~hjm/stats

example:

 $ ls -l | scut -f=4 | stats                
Sum       9702066453
Number    501
Mean      19365402.1017964
Median    4451
Mode      4096  
NModes    15
Min       0
Max       2019645440
Range     2019645440
Variance  1.96315423371944e+16
Std_Dev   140112605.91822
SEM       6259769.58393047
Skew      10.2405932543676
Std_Skew  93.5768354979843
Kurtosis  117.69005473429

(scut is a slower, but arguably easier to version of cut): http://moo.nac.uci.edu/~hjm/scut described: http://moo.nac.uci.edu/~hjm/scut_cols_HOWTO.html

$\endgroup$
1
$\begingroup$

Another tool: tsv-summarize from eBay's TSV Utilities. Supports many of the basic summary statistics, like min, max, mean, median, quantiles, standard deviation, MAD, and a few more. It is intended for large datasets and supports multiple fields and grouping by key. Output is tab separated. An example for the sequence of numbers 1 to 1000, one per line:

$ seq 1000 | tsv-summarize --min 1 --max 1 --median 1 --sum 1
1   1000    500.5   500500

Headers are normally generated from a header line in the input. If the input has no header one can be added using the -w switch:

$ seq 1000 | tsv-summarize -w --min 1 --max 1 --median 1 --sum 1
field1_min  field1_max  field1_median   field1_sum
1   1000    500.5   500500

Disclaimer: I'm the author.

$\endgroup$
0
$\begingroup$

Too much memory and processor power, folks. Using R for something like this is roughly like getting a sledgehammer to kill a mosquito. Use your favorite language and implement a provisional means algorithm. For the mean: $$\bar{x}_n = \frac{(n-1)\,\bar{x}_{n-1} + x_n}{n}$$; and for the variance:$$s^2_n = \frac{S_n}{n-1}$$ $$S_n = S_{n-1} + (x_n-\bar{x}_{n-1})(x_n-\bar{x}_n).$$

Take $\bar{x}_0 = S_0 = 0$ as starting values. Modifications are available for weighted analyses. You can do the computations with two double precision reals and a counter.

$\endgroup$
2
  • $\begingroup$ Try it with some $x_i$ equivalent to FLOAT_MAX-1.0 or with $x_i-x_{i+1}$ very small but $x_i-x_{i-1}$ very large. $\endgroup$
    – mbaitoff
    Jul 18, 2014 at 2:59
  • $\begingroup$ This is actually what clistats does (see answer for details and other features). $\endgroup$
    – dpmcmlxxvi
    Jun 25, 2015 at 19:46

Not the answer you're looking for? Browse other questions tagged or ask your own question.