diff --git a/README.md b/README.md index 28ba526..2bd08cc 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,13 @@ iex> samples = [1, 3.0, 2.35, 11.0, 1.37, 35, 5.5, 10, 0, 2.35] # calculate all available statistics at once, efficiently reusing already calculated values iex> Statistex.statistics(samples) %Statistex{ + total: 71.57, average: 7.156999999999999, + variance: 109.66060111111112, + standard_deviation: 10.471895774457991, + standard_deviation_ratio: 1.4631683351205802, + median: 2.675, + percentiles: %{25 => 1.2775, 50 => 2.675, 75 => 10.25}, frequency_distribution: %{ 0 => 1, 1 => 1, @@ -40,16 +46,13 @@ iex> Statistex.statistics(samples) 5.5 => 1, 11.0 => 1 }, - maximum: 35, - median: 2.675, - minimum: 0, mode: 2.35, - percentiles: %{50 => 2.675}, - sample_size: 10, - standard_deviation: 10.47189577445799, - standard_deviation_ratio: 1.46316833512058, - total: 71.57, - variance: 109.6606011111111 + minimum: 0, + maximum: 35, + lower_outlier_bound: -12.18125, + upper_outlier_bound: 23.708750000000002, + outliers: [35], + sample_size: 10 } # or just calculate the value you need iex> Statistex.average(samples) @@ -63,6 +66,34 @@ iex> Statistex.average(samples, sample_size: 10) # output is likely also very different from when you have statistics. iex> Statistex.statistics([]) ** (ArgumentError) Passed an empty list ([]) to calculate statistics from, please pass a list containing at least one number. +# You can exclude outliers from the calculation of statistics +iex> Statistex.statistics(samples, exclude_outliers: true) +%Statistex{ + total: 36.57, + average: 4.0633333333333335, + variance: 15.696975, + standard_deviation: 3.96194081227875, + standard_deviation_ratio: 0.9750469595435808, + median: 2.35, + percentiles: %{25 => 1.185, 50 => 2.35, 75 => 7.75}, + frequency_distribution: %{ + 0 => 1, + 1 => 1, + 10 => 1, + 1.37 => 1, + 2.35 => 2, + 3.0 => 1, + 5.5 => 1, + 11.0 => 1 + }, + mode: 2.35, + minimum: 0, + maximum: 11.0, + lower_outlier_bound: -12.18125, + upper_outlier_bound: 23.708750000000002, + outliers: [35], + sample_size: 9 +} ``` ## Supported Statistics @@ -83,6 +114,8 @@ Statistics currently supported: * standard_deviation_ratio * total * variance +* outliers (determining outliers) +* outlier bounds (lower and upper bound of when samples start being considered outliers) ## Alternatives diff --git a/lib/statistex.ex b/lib/statistex.ex index 8b67d9c..c98b945 100644 --- a/lib/statistex.ex +++ b/lib/statistex.ex @@ -462,7 +462,7 @@ defmodule Statistex do Calculates the value at the `percentile_rank`-th percentile. Think of this as the value below which `percentile_rank` percent of the samples lie. - For example, if `Statistex.percentile(samples, 99) == 123.45`, + For example, if `Statistex.percentiles(samples, 99) == 123.45`, 99% of samples are less than 123.45. Passing a number for `percentile_rank` calculates a single percentile. @@ -513,6 +513,10 @@ defmodule Statistex do @spec percentiles(samples, number | [number(), ...]) :: percentiles() defdelegate percentiles(samples, percentiles, options), to: Percentile + + @doc """ + See `percentiles/3`. + """ defdelegate percentiles(samples, percentiles), to: Percentile @doc """ @@ -703,6 +707,8 @@ defmodule Statistex do Returns: `{outliers, remaining_samples`} where `remaining_samples` has the outliers removed. + `Argumenterror` is raised if the given list is empty. + ## Options * `:outlier_bounds` - if you already have calculated the outlier bounds. * `:percentiles` - you can pass it a map of calculated percentiles (25th and 75th are needed). @@ -723,6 +729,9 @@ defmodule Statistex do iex> Statistex.outliers([50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 99, 99, 99]) {[99, 99, 99], [50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50]} + + iex> Statistex.outliers([]) + ** (ArgumentError) Passed an empty list ([]) to calculate statistics from, please pass a list containing at least one number. """ @spec outliers(samples, keyword) :: {samples | [], samples} def outliers(samples, options \\ []) do diff --git a/mix.exs b/mix.exs index 623ac40..aea4109 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule Statistex.MixProject do use Mix.Project - @version "1.0.0" + @version "1.1.0" def project do [ app: :statistex, diff --git a/mix.lock b/mix.lock index efe874f..1cc051d 100644 --- a/mix.lock +++ b/mix.lock @@ -2,10 +2,10 @@ "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, - "earmark": {:hex, :earmark, "1.4.47", "7e7596b84fe4ebeb8751e14cbaeaf4d7a0237708f2ce43630cfd9065551f94ca", [:mix], [], "hexpm", "3e96bebea2c2d95f3b346a7ff22285bc68a99fbabdad9b655aa9c6be06c698f8"}, + "earmark": {:hex, :earmark, "1.4.48", "5f41e579d85ef812351211842b6e005f6e0cef111216dea7d4b9d58af4608434", [:mix], [], "hexpm", "a461a0ddfdc5432381c876af1c86c411fd78a25790c75023c7a4c035fdc858f9"}, "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, - "ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"}, + "ex_doc": {:hex, :ex_doc, "0.38.2", "504d25eef296b4dec3b8e33e810bc8b5344d565998cd83914ffe1b8503737c02", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "732f2d972e42c116a70802f9898c51b54916e542cc50968ac6980512ec90f42b"}, "excoveralls": {:hex, :excoveralls, "0.18.5", "e229d0a65982613332ec30f07940038fe451a2e5b29bce2a5022165f0c9b157e", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "523fe8a15603f86d64852aab2abe8ddbd78e68579c8525ae765facc5eae01562"}, "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "inch_ex": {:hex, :inch_ex, "2.0.0", "24268a9284a1751f2ceda569cd978e1fa394c977c45c331bb52a405de544f4de", [:mix], [{:bunt, "~> 0.2", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "96d0ec5ecac8cf63142d02f16b7ab7152cf0f0f1a185a80161b758383c9399a8"},