1
1
# ' @importFrom vctrs field vec_cast new_rcrd
2
- new_quantiles <- function (values = double(), quantile_levels = double()) {
2
+ new_quantiles <- function (values = double(1 ), quantile_levels = double(1 )) {
3
3
arg_is_probabilities(quantile_levels )
4
4
5
5
vec_cast(values , double())
6
6
vec_cast(quantile_levels , double())
7
+ values <- unname(values )
8
+ if (length(values ) == 0L ) {
9
+ return (new_rcrd(
10
+ list (
11
+ values = rep(NA_real_ , length(quantile_levels )),
12
+ quantile_levels = quantile_levels
13
+ ),
14
+ class = c(" dist_quantiles" , " dist_default" )
15
+ ))
16
+ }
7
17
stopifnot(length(values ) == length(quantile_levels ))
18
+
8
19
stopifnot(! vctrs :: vec_duplicate_any(quantile_levels ))
9
20
if (is.unsorted(quantile_levels )) {
10
21
o <- vctrs :: vec_order(quantile_levels )
@@ -37,30 +48,49 @@ format.dist_quantiles <- function(x, digits = 2, ...) {
37
48
38
49
# ' A distribution parameterized by a set of quantiles
39
50
# '
40
- # ' @param values A vector of values
41
- # ' @param quantile_levels A vector of probabilities corresponding to `values`
51
+ # ' @param values A vector (or list of vectors) of values.
52
+ # ' @param quantile_levels A vector (or list of vectors) of probabilities
53
+ # ' corresponding to `values`.
54
+ # '
55
+ # ' When creating multiple sets of `values`/`quantile_levels` resulting in
56
+ # ' different distributions, the sizes must match. See the examples below.
57
+ # '
58
+ # ' @return A vector of class `"distribution"`.
42
59
# '
43
60
# ' @export
44
61
# '
45
62
# ' @examples
46
- # ' dstn <- dist_quantiles(list(1:4, 8:11), list(c(.2, .4, .6, .8)))
63
+ # ' dist_quantiles(1:4, 1:4 / 5)
64
+ # ' dist_quantiles(list(1:3, 1:4), list(1:3 / 4, 1:4 / 5))
65
+ # ' dstn <- dist_quantiles(list(1:4, 8:11), c(.2, .4, .6, .8))
66
+ # ' dstn
67
+ # '
47
68
# ' quantile(dstn, p = c(.1, .25, .5, .9))
48
69
# ' median(dstn)
49
70
# '
50
71
# ' # it's a bit annoying to inspect the data
51
72
# ' distributional::parameters(dstn[1])
52
73
# ' nested_quantiles(dstn[1])[[1]]
53
74
# '
54
- # ' dist_quantiles(1:4, 1:4 / 5)
55
75
# ' @importFrom vctrs as_list_of vec_recycle_common new_vctr
56
76
dist_quantiles <- function (values , quantile_levels ) {
57
- if (! is.list(values )) values <- list (values )
58
- if (! is.list(quantile_levels )) quantile_levels <- list (quantile_levels )
77
+ if (! is.list(quantile_levels )) {
78
+ assert_numeric(quantile_levels , lower = 0 , upper = 1 , any.missing = FALSE , min.len = 1L )
79
+ quantile_levels <- list (quantile_levels )
80
+ }
81
+ if (! is.list(values )) {
82
+ if (length(values ) == 0L ) values <- NA_real_
83
+ values <- list (values )
84
+ }
59
85
60
86
values <- as_list_of(values , .ptype = double())
61
87
quantile_levels <- as_list_of(quantile_levels , .ptype = double())
62
88
args <- vec_recycle_common(values = values , quantile_levels = quantile_levels )
63
- qntls <- as_list_of(map2(args $ values , args $ quantile_levels , new_quantiles ))
89
+
90
+ qntls <- as_list_of(
91
+ map2(args $ values , args $ quantile_levels , new_quantiles ),
92
+ .ptype = new_quantiles(NA_real_ , 0.5 )
93
+ )
64
94
new_vctr(qntls , class = " distribution" )
65
95
}
66
96
@@ -87,59 +117,6 @@ validate_dist_quantiles <- function(values, quantile_levels) {
87
117
}
88
118
89
119
90
- # ' Summarize a distribution with a set of quantiles
91
- # '
92
- # ' @param x a `distribution` vector
93
- # ' @param probs a vector of probabilities at which to calculate quantiles
94
- # ' @param ... additional arguments passed on to the `quantile` method
95
- # '
96
- # ' @return a `distribution` vector containing `dist_quantiles`
97
- # ' @export
98
- # '
99
- # ' @examples
100
- # ' library(distributional)
101
- # ' dstn <- dist_normal(c(10, 2), c(5, 10))
102
- # ' extrapolate_quantiles(dstn, probs = c(.25, 0.5, .75))
103
- # '
104
- # ' dstn <- dist_quantiles(list(1:4, 8:11), list(c(.2, .4, .6, .8)))
105
- # ' # because this distribution is already quantiles, any extra quantiles are
106
- # ' # appended
107
- # ' extrapolate_quantiles(dstn, probs = c(.25, 0.5, .75))
108
- # '
109
- # ' dstn <- c(
110
- # ' dist_normal(c(10, 2), c(5, 10)),
111
- # ' dist_quantiles(list(1:4, 8:11), list(c(.2, .4, .6, .8)))
112
- # ' )
113
- # ' extrapolate_quantiles(dstn, probs = c(.25, 0.5, .75))
114
- extrapolate_quantiles <- function (x , probs , ... ) {
115
- UseMethod(" extrapolate_quantiles" )
116
- }
117
-
118
- # ' @export
119
- # ' @importFrom vctrs vec_data
120
- extrapolate_quantiles.distribution <- function (x , probs , ... ) {
121
- arg_is_probabilities(probs )
122
- dstn <- lapply(vec_data(x ), extrapolate_quantiles , probs = probs , ... )
123
- new_vctr(dstn , vars = NULL , class = " distribution" )
124
- }
125
-
126
- # ' @export
127
- extrapolate_quantiles.dist_default <- function (x , probs , ... ) {
128
- values <- quantile(x , probs , ... )
129
- new_quantiles(values = values , quantile_levels = probs )
130
- }
131
-
132
- # ' @export
133
- extrapolate_quantiles.dist_quantiles <- function (x , probs , ... ) {
134
- new_values <- quantile(x , probs , ... )
135
- quantile_levels <- field(x , " quantile_levels" )
136
- values <- field(x , " values" )
137
- new_quantiles(
138
- values = c(values , new_values ),
139
- quantile_levels = c(quantile_levels , probs )
140
- )
141
- }
142
-
143
120
is_dist_quantiles <- function (x ) {
144
121
is_distribution(x ) & all(stats :: family(x ) == " quantiles" )
145
122
}
@@ -183,18 +160,20 @@ quantile.dist_quantiles <- function(x, p, ..., middle = c("cubic", "linear")) {
183
160
quantile_extrapolate <- function (x , tau_out , middle ) {
184
161
tau <- field(x , " quantile_levels" )
185
162
qvals <- field(x , " values" )
186
- r <- range( tau , na.rm = TRUE )
163
+ nas <- is.na( qvals )
187
164
qvals_out <- rep(NA , length(tau_out ))
165
+ qvals <- qvals [! nas ]
166
+ tau <- tau [! nas ]
188
167
189
168
# short circuit if we aren't actually extrapolating
190
169
# matches to ~15 decimals
191
170
if (all(tau_out %in% tau )) {
192
171
return (qvals [match(tau_out , tau )])
193
172
}
194
- if (length(qvals ) < 2 ) {
195
- cli :: cli_abort(c(
173
+ if (length(tau ) < 2 ) {
174
+ cli :: cli_abort(
196
175
" Quantile extrapolation is not possible with fewer than 2 quantiles."
197
- ))
176
+ )
198
177
return (qvals_out )
199
178
}
200
179
0 commit comments