WeightedRandom.Utils.Analysis (weighted_random v1.0.0)

Copy Markdown View Source

Utilities for backend developers to test the accuracy of their results.

Summary

Functions

Determine whether two numbers are equal; within a very small rounding error.

Given a list of probabilities, and a sample of random results, determine how close those results were to their probabilities.

Given a list of random values, determine the probability of each value.

Given a list of random values, determine the probability of each value. Return list is in the same order as the second argument.

Given the list of outcomes, and list of weights, return the list of probabilities

Returns a map of %{index => outcome}

Given a list of expected probabilities, and a list of actual results (as indices), determine whether they are all within the tolerance level.

Returns a map of %{outcome => index}

Sum a list of numbers, and find it's delta from a target number

Determine whether a list of numbers, when summed, roughly equal the target

Functions

equalish?(left, right)

Determine whether two numbers are equal; within a very small rounding error.

This function is just a wrapper around the Equalish library, but allows list comparisons.

Examples

iex> equalish?(0.5, 0.499999999, 0.01)
true
iex> equalish?(0.5, 0.6, 0.01)
false
iex> equalish?([0.5, 0.2, 0.3], [0.4999, 0.2001, 0.3])
true

equalish?(left, right, tolerance)

@spec equalish?(
  left :: number() | [number()],
  right :: number() | [number()],
  tolerance :: WeightedRandom.Utils.Types.tolerance()
) :: boolean()

get_delta(expected, results)

@spec get_delta(expected :: [float()], results :: list()) :: [float()]

Given a list of probabilities, and a sample of random results, determine how close those results were to their probabilities.

This returns the absolute values, so they will never be negative.

Examples

iex> probs = [0.25, 0.5, 0.25]
iex> results = [0, 1, 1, 2]
iex> get_delta(probs, results)
[0.0, 0.0, 0.0]

iex> probs = [0.5, 0.5]
iex> results = [0, 1, 1, 1]
iex> get_delta(probs, results)
[0.25, 0.25]

get_frequency_of_results(results)

@spec get_frequency_of_results(results :: list()) :: %{
  optional(result :: any()) => count :: integer()
}

Given a list of random values, determine the probability of each value.

Examples

iex> get_frequency_of_results([0, 1, 2, 2, 2, 2, 2, 2])
%{0 => 0.125, 1 => 0.125, 2 => 0.75}

get_probabilities_from_results(results, outcomes)

@spec get_probabilities_from_results(results :: list(), outcomes :: list()) :: [
  float()
]

Given a list of random values, determine the probability of each value. Return list is in the same order as the second argument.

This is basically the inverse of WeightedRandom.rand_p/2

Examples

iex> get_probabilities_from_results([1, 2, 2, 2, 2, 2, 2, 0], 0..2)
[0.125, 0.125, 0.75]

get_probabilities_from_weights(outcomes, weights, opts \\ [])

@spec get_probabilities_from_weights(
  outcomes :: WeightedRandom.Utils.Types.outcomes(),
  weights :: [WeightedRandom.Utils.Types.weight_spec()],
  opts :: list()
) :: [float()]

Given the list of outcomes, and list of weights, return the list of probabilities

Examples

iex> get_probabilities_from_weights(1..6, [%{target: 3, weight: 2}], outcome_type: :value)
[0.125, 0.125, 0.375, 0.125, 0.125, 0.125]

index_to_outcome_table(outcomes, opts)

@spec index_to_outcome_table(
  outcomes :: WeightedRandom.Utils.Types.outcomes(),
  opts :: list()
) :: %{
  optional(integer()) => any()
}

Returns a map of %{index => outcome}

Examples

iex> outcomes = 100..130//10
iex> index_to_outcome_table(outcomes, [index: true])
%{0 => 100, 1 => 110, 2 => 120, 3 => 130}

match_probability?(expected, results, tolerance \\ 0.05)

@spec match_probability?(
  expected :: [float()],
  results :: [WeightedRandom.Utils.Types.index()],
  tolerance :: float()
) :: boolean()

Given a list of expected probabilities, and a list of actual results (as indices), determine whether they are all within the tolerance level.

If the results have a very large sample size, then you should be able lower the tolerance.

This function will be more accurate with a higher sample size

Examples

iex> match_probability?([0.75, 0.25], [0, 1, 0, 0])
true
iex> match_probability?([0.75, 0.25], [0, 1, 0, 1])
false

outcome_to_index_table(outcomes, opts)

@spec outcome_to_index_table(
  outcomes :: WeightedRandom.Utils.Types.outcomes(),
  opts :: list()
) :: %{
  optional(integer()) => any()
}

Returns a map of %{outcome => index}

Examples

iex> outcomes = 100..130//10
iex> outcome_to_index_table(outcomes, [index: true])
%{100 => 0, 110 => 1, 120 => 2, 130 => 3}

sum_delta(numbers, target)

@spec sum_delta(numbers :: [number()], target :: number()) :: number()

Sum a list of numbers, and find it's delta from a target number

Examples

iex> sum_delta([0.5, 0.25, 0.25], 1.0)
0.0
iex> sum_delta([0.5, 0.25, 0.25, 0.5], 1.0)
0.5

sum_equalish?(li, target, tolerance \\ 0.05)

@spec sum_equalish?(
  li :: [number()],
  target :: number(),
  tolerance :: WeightedRandom.Utils.Types.tolerance()
) :: boolean()

Determine whether a list of numbers, when summed, roughly equal the target

Examples

iex> sum_equalish?([0.1, 0.2], 0.3)
true