Skip to content

Commit dbc16af

Browse files
committed
median: add subroutine to compute median of elements of an array
1 parent 8dddff4 commit dbc16af

File tree

4 files changed

+417
-36
lines changed

4 files changed

+417
-36
lines changed

doc/specs/stdlib_stats.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ The Pearson correlation between two rows (or columns), say `x` and `y`, of `arra
2626

2727
`result = [[stdlib_stats(module):corr(interface)]](array, dim [, mask])`
2828

29+
### Class
30+
31+
Generic subroutine
32+
2933
### Arguments
3034

3135
`array`: Shall be a rank-1 or a rank-2 array of type `integer`, `real`, or `complex`.
@@ -83,6 +87,10 @@ The scaling can be changed with the logical argument `corrected`. If `corrected`
8387

8488
`result = [[stdlib_stats(module):cov(interface)]](array, dim [, mask [, corrected]])`
8589

90+
### Class
91+
92+
Generic subroutine
93+
8694
### Arguments
8795

8896
`array`: Shall be a rank-1 or a rank-2 array of type `integer`, `real`, or `complex`.
@@ -134,6 +142,10 @@ Returns the mean of all the elements of `array`, or of the elements of `array` a
134142

135143
`result = [[stdlib_stats(module):mean(interface)]](array, dim [, mask])`
136144

145+
### Class
146+
147+
Generic subroutine
148+
137149
### Arguments
138150

139151
`array`: Shall be an array of type `integer`, `real`, or `complex`.
@@ -166,6 +178,75 @@ program demo_mean
166178
end program demo_mean
167179
```
168180

181+
## `median` - median of array elements
182+
183+
### Status
184+
185+
Experimental
186+
187+
### Description
188+
189+
Returns the median of all the elements of `array`, or of the elements of `array` along dimension `dim` if provided, and if the corresponding element in `mask` is `true`.
190+
191+
After that the elements are sorted in an increasing order, e.g. `array_sorted =
192+
sort(array)`, the median of the elements of `array` are defined as, if
193+
`n = size(array)` is an even number:
194+
195+
```
196+
median(array) = array_sorted( floor( (n + 1) / 2.))
197+
```
198+
199+
or as if `n` is an odd number:
200+
201+
```
202+
median(array) = mean( array_sorted( floor( (n + 1) / 2.):floor( (n + 1) / 2.) + 1 ) )
203+
```
204+
205+
The array is sorted using the subroutine `sort` provided by the `stdlib_sorting`
206+
module.
207+
208+
### Syntax
209+
210+
`result = [[stdlib_stats(module):median(interface)]](array [, mask])`
211+
212+
`result = [[stdlib_stats(module):median(interface)]](array, dim [, mask])`
213+
214+
### Class
215+
216+
Generic subroutine
217+
218+
### Arguments
219+
220+
`array`: Shall be an array of type `integer` or `real`.
221+
222+
`dim`: Shall be a scalar of type `integer` with a value in the range from 1 to `n`, where `n` is the rank of `array`.
223+
224+
`mask` (optional): Shall be of type `logical` and either a scalar or an array of the same shape as `array`.
225+
226+
### Return value
227+
228+
If `array` is of type `real`, the result is of the same type as `array`.
229+
If `array` is of type `integer`, the result is of type `real(dp)`.
230+
231+
If `dim` is absent, a scalar with the median of all elements in `array` is returned. Otherwise, an array of rank `n-1`, where `n` equals the rank of `array`, and a shape similar to that of `array` with dimension `dim` dropped is returned.
232+
233+
If `mask` is specified, the result is the median of all elements of `array` corresponding to `true` elements of `mask`. If every element of `mask` is `false`, the result is IEEE `NaN`.
234+
235+
### Example
236+
237+
```fortran
238+
program demo_median
239+
use stdlib_stats, only: median
240+
implicit none
241+
real :: x(1:6) = [ 1., 2., 3., 4., 5., 6. ]
242+
real :: y(1:2, 1:3) = reshape([ 1., 2., 3., 4., 5., 6. ], [ 2, 3])
243+
print *, median(x) !returns 3.5
244+
print *, median(y) !returns 3.5
245+
print *, median(y, 1) !returns [ 1.5, 3.5, 5.5 ]
246+
print *, median(y, 1,y > 3.) !returns [ NaN, 4.0, 5.5 ]
247+
end program demo_median
248+
```
249+
169250
## `moment` - central moments of array elements
170251

171252
### Status
@@ -199,6 +280,10 @@ The _k_-th order moment about `center` is defined as :
199280

200281
`result = [[stdlib_stats(module):moment(interface)]](array, order, dim [, center [, mask]])`
201282

283+
### Class
284+
285+
Generic subroutine
286+
202287
### Arguments
203288

204289
`array`: Shall be an array of type `integer`, `real`, or `complex`.
@@ -264,6 +349,10 @@ The use of the term `n-1` for scaling is called Bessel 's correction. The scalin
264349

265350
`result = [[stdlib_stats(module):var(interface)]](array, dim [, mask [, corrected]])`
266351

352+
### Class
353+
354+
Generic subroutine
355+
267356
### Arguments
268357

269358
`array`: Shall be an array of type `integer`, `real`, or `complex`.

src/stdlib_stats.fypp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,54 @@ module stdlib_stats
355355
#:endfor
356356
#:endfor
357357

358+
#:for k1, t1 in REAL_KINDS_TYPES
359+
#:for rank in RANKS
360+
#:set RName = rname('median_mask_all',rank, t1, k1)
361+
module function ${RName}$(x, mask) result(res)
362+
${t1}$, intent(in) :: x${ranksuffix(rank)}$
363+
logical, intent(in) :: mask${ranksuffix(rank)}$
364+
${t1}$ :: res
365+
end function ${RName}$
366+
#:endfor
367+
#:endfor
368+
369+
#:for k1, t1 in INT_KINDS_TYPES
370+
#:for rank in RANKS
371+
#:set RName = rname('median_mask_all',rank, t1, k1,'dp')
372+
module function ${RName}$(x, mask) result(res)
373+
${t1}$, intent(in) :: x${ranksuffix(rank)}$
374+
logical, intent(in) :: mask${ranksuffix(rank)}$
375+
real(dp) :: res
376+
end function ${RName}$
377+
#:endfor
378+
#:endfor
379+
380+
381+
382+
#:for k1, t1 in REAL_KINDS_TYPES
383+
#:for rank in RANKS
384+
#:set RName = rname('median_mask',rank, t1, k1)
385+
module function ${RName}$(x, dim, mask) result(res)
386+
${t1}$, intent(in) :: x${ranksuffix(rank)}$
387+
integer, intent(in) :: dim
388+
logical, intent(in) :: mask${ranksuffix(rank)}$
389+
${t1}$ :: res${reduced_shape('x', rank, 'dim')}$
390+
end function ${RName}$
391+
#:endfor
392+
#:endfor
393+
394+
395+
#:for k1, t1 in INT_KINDS_TYPES
396+
#:for rank in RANKS
397+
#:set RName = rname('median_mask',rank, t1, k1, 'dp')
398+
module function ${RName}$(x, dim, mask) result(res)
399+
${t1}$, intent(in) :: x${ranksuffix(rank)}$
400+
integer, intent(in) :: dim
401+
logical, intent(in) :: mask${ranksuffix(rank)}$
402+
real(dp) :: res${reduced_shape('x', rank, 'dim')}$
403+
end function ${RName}$
404+
#:endfor
405+
#:endfor
358406

359407

360408

0 commit comments

Comments
 (0)