mc_forecast 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 387e653e97a687f2ab7618e2612c38fae72ddb5bc87485b44998005cab548d3d
4
- data.tar.gz: 161aca02d0cb2ded0c143908ee9d4747078bd73888974d026b08d8039ccb117a
3
+ metadata.gz: 82e81b59b88ffa6eadba70aef437ecec5c040b890b19d7f64f8237eb59fc7c56
4
+ data.tar.gz: 729b9f9d931b338f5860427d1aaba73aea35c847eedb018d72c39a7486c7f551
5
5
  SHA512:
6
- metadata.gz: f075afc3d8b5c2c234c50fc2b58ea66da44a6bb6cfbc3058982c6a131aa374576b1ec7c953bb1b21f81c0cddba46233be67c8fddc09887049f060db37f903848
7
- data.tar.gz: c0e17a7551d1ba892b7d372e1a1424eda9b8ee3231b68420e6a03e773cde672d6fad125529f99e72d7a1c810aed6b30b6a6ac4e12ebbfa9adfb06a96b8174454
6
+ metadata.gz: 4ce13d962a1c9e82f52e101387f6c8627fdac52187000e5ceb5a25bc7513bc9929cd94d6fc6faaf5196f7bcc90336bb69be642c774abe93a205b43464bbc20f1
7
+ data.tar.gz: ea2d982df7f53a36558969c1d8361ea477d817895f92a4118cb23472eaa3066b85ce9efffcc12f804894facf1303f8dffe68c2b2bb9fd8865125d0ba516a41fd
@@ -2,7 +2,7 @@ require "deep_dup"
2
2
 
3
3
  module McForecast
4
4
  class Simulation
5
- def run(init_state: nil, trials: 1_000, steps: 1, quantiles: [0.025, 0.975])
5
+ def run(init_state: nil, trials: 1_000, steps: 1, quantiles: [0.025, 0.16, 0.84, 0.975])
6
6
  events = {}
7
7
  (0..trials - 1).each do |trial|
8
8
  state = DeepDup.deep_dup(init_state)
@@ -24,33 +24,51 @@ module McForecast
24
24
 
25
25
  # Return an analysis of the events, containing:
26
26
  # { event_name:
27
- # { mean: [...], # per step
27
+ # {
28
+ # sum: { mean: ...,
29
+ # quantiles:
30
+ # { 0.025: ..., 0.975: ... }},
31
+ # mean: [...], # per step
28
32
  # quantiles:
29
33
  # { 0.025: [...],
30
34
  # 0.975: [...]
31
35
  # }}}
32
36
  def analyze(events, quantiles)
33
37
  events.transform_values do |steps| # array(steps) of arrays(trials)
34
- a = if quantiles.any?
35
- # only need to sort if we request answers on any quantiles
36
- steps.map do |trials|
37
- # could avoid sorting with some creativity, but probably fine for our data lengths so far
38
- trials.sort.values_at(*quantile_indices(trials.length, quantiles))
39
- end.transpose # a[step][]
40
- else
41
- []
42
- end
43
-
44
38
  {
45
- mean: steps.map { |trials| Rational(trials.sum || 0, trials.length) },
46
- quantiles: quantiles.zip(a).to_h
39
+ sum: sum(steps, quantiles),
40
+ # besides the total sum we may want to have a sum for multiples of our base period
41
+ # (or week/month/quarter/year but that gets a bit complicated)
42
+ mean: steps.map { |trials| (trials.sum || 0).to_f / trials.length },
43
+ quantiles: quantiles.zip(step_quantiles(quantiles, steps)).to_h
47
44
  }
48
45
  end
49
46
  end
50
47
 
51
- def quantile_indices(n_trials, quantiles)
48
+ def sum(steps, quantiles)
49
+ sums = steps.transpose.map(&:sum) # gives a sum of this event, per trial
50
+ {
51
+ mean: (sums.sum || 0).to_f / steps[0].length,
52
+ # sort all of the sums, and take the elements closest to the chosen quantiles, and then make a nice hash
53
+ quantiles: quantiles.zip(sums.sort.values_at(*quantile_indices(steps[0].length, quantiles))).to_h
54
+ }
55
+ end
56
+
57
+ def step_quantiles(quantiles, steps)
58
+ if quantiles.any?
59
+ # only need to sort if we request answers on any quantiles
60
+ steps.map do |trials|
61
+ # could avoid sorting with some creativity, but probably fine for our data lengths so far
62
+ trials.sort.values_at(*quantile_indices(trials.length, quantiles))
63
+ end.transpose # a[step][]
64
+ else
65
+ []
66
+ end
67
+ end
68
+
69
+ def quantile_indices(count, quantiles)
52
70
  quantiles.map do |q|
53
- (q * (n_trials - 1)).round.to_i.clamp(0, n_trials - 1)
71
+ (q * (count - 1)).round.to_i.clamp(0, count - 1)
54
72
  end
55
73
  end
56
74
  end
@@ -1,3 +1,3 @@
1
1
  module McForecast
2
- VERSION = "0.1.1".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mc_forecast
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daan van Vugt
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-08 00:00:00.000000000 Z
11
+ date: 2024-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deep_dup