@@ -3260,293 +3260,6 @@ unittest
3260
3260
assert (x.sliced.standardDeviation! float .approxEqual(sqrt(54.76562 / 11 )));
3261
3261
}
3262
3262
3263
- /+ +
3264
- Calculates the dispersion of the input.
3265
-
3266
- For an input `x`, this function first centers `x` by subtracting each `e` in `x`
3267
- by the result of `centralTendency`, then it transforms the centered values using
3268
- the function `transform`, and then finally summarizes that information using
3269
- the `summarize` funcion.
3270
-
3271
- The default functions provided are equivalent to calculating the population
3272
- variance. The `centralTendency` default is the `mean` function, which results
3273
- in the input being centered about the mean. The default `transform` function
3274
- will square the centered values. The default `summarize` function is `mean`,
3275
- which will return the mean of the squared centered values.
3276
-
3277
- Params:
3278
- centralTendency = function that will produce the value that the input is centered about, default is `mean`
3279
- transform = function to transform centered values, default squares the centered values
3280
- summarize = function to summarize the transformed centered values, default is `mean`
3281
-
3282
- Returns:
3283
- The dispersion of the input
3284
- +/
3285
- template dispersion (
3286
- alias centralTendency = mean,
3287
- alias transform = " a * a" ,
3288
- alias summarize = mean)
3289
- {
3290
- import mir.functional: naryFun;
3291
- import mir.ndslice.slice: Slice, SliceKind, sliced, hasAsSlice;
3292
-
3293
- static if (__traits(isSame, naryFun! transform, transform))
3294
- {
3295
- /+ +
3296
- Params:
3297
- slice = slice
3298
- +/
3299
- @fmamath auto dispersion(Iterator, size_t N, SliceKind kind)(
3300
- Slice! (Iterator, N, kind) slice)
3301
- {
3302
- import core.lifetime : move;
3303
- import mir.ndslice.topology: map;
3304
-
3305
- return summarize (slice.move.center! centralTendency.map! transform);
3306
- }
3307
-
3308
- // / ditto
3309
- @fmamath auto dispersion(T)(scope const T[] ar... )
3310
- {
3311
- return dispersion (ar.sliced);
3312
- }
3313
-
3314
- // / ditto
3315
- @fmamath auto dispersion(T)(T withAsSlice)
3316
- if (hasAsSlice! T)
3317
- {
3318
- return dispersion (withAsSlice.asSlice);
3319
- }
3320
- }
3321
- else
3322
- alias dispersion = .dispersion! (centralTendency, naryFun! transform, summarize);
3323
- }
3324
-
3325
- // /
3326
- version (mir_test)
3327
- @safe pure nothrow
3328
- unittest
3329
- {
3330
- import mir.ndslice.slice: sliced;
3331
- import mir.math.common: approxEqual;
3332
- import mir.functional: naryFun;
3333
-
3334
- assert (dispersion([1.0 , 2 , 3 ]).approxEqual(2.0 / 3 ));
3335
-
3336
- assert (dispersion([1.0 + 3i, 2 , 3 ]).approxEqual((- 4.0 - 6i) / 3 ));
3337
-
3338
- assert (dispersion! (mean! float , " a * a" , mean! float )([0 , 1 , 2 , 3 , 4 , 5 ].sliced(3 , 2 )).approxEqual(17.5 / 6 ));
3339
-
3340
- static assert (is (typeof (dispersion! (mean! float , " a ^^ 2" , mean! float )([1 , 2 , 3 ])) == float ));
3341
- }
3342
-
3343
- // / Dispersion of vector
3344
- version (mir_test)
3345
- @safe pure nothrow
3346
- unittest
3347
- {
3348
- import mir.ndslice.slice: sliced;
3349
- import mir.math.common: approxEqual;
3350
-
3351
- auto x = [0.0 , 1.0 , 1.5 , 2.0 , 3.5 , 4.25 ,
3352
- 2.0 , 7.5 , 5.0 , 1.0 , 1.5 , 0.0 ].sliced;
3353
-
3354
- assert (x.dispersion.approxEqual(54.76562 / 12 ));
3355
- }
3356
-
3357
- // / Dispersion of matrix
3358
- version (mir_test)
3359
- @safe pure
3360
- unittest
3361
- {
3362
- import mir.ndslice.fuse: fuse;
3363
- import mir.math.common: approxEqual;
3364
-
3365
- auto x = [
3366
- [0.0 , 1.0 , 1.5 , 2.0 , 3.5 , 4.25 ],
3367
- [2.0 , 7.5 , 5.0 , 1.0 , 1.5 , 0.0 ]
3368
- ].fuse;
3369
-
3370
- assert (x.dispersion.approxEqual(54.76562 / 12 ));
3371
- }
3372
-
3373
- // / Column dispersion of matrix
3374
- version (mir_test)
3375
- @safe pure
3376
- unittest
3377
- {
3378
- import mir.ndslice.fuse: fuse;
3379
- import mir.ndslice.topology: alongDim, byDim, map;
3380
- import mir.math.common: approxEqual;
3381
- import mir.algorithm.iteration: all;
3382
-
3383
- auto x = [
3384
- [0.0 , 1.0 , 1.5 , 2.0 ],
3385
- [3.5 , 4.25 , 2.0 , 7.5 ],
3386
- [5.0 , 1.0 , 1.5 , 0.0 ]
3387
- ].fuse;
3388
- auto result = [13.16667 / 3 , 7.041667 / 3 , 0.1666667 / 3 , 30.16667 / 3 ];
3389
-
3390
- // Use byDim or alongDim with map to compute dispersion of row/column.
3391
- assert (x.byDim! 1. map! dispersion.all! approxEqual(result));
3392
- assert (x.alongDim! 0. map! dispersion.all! approxEqual(result));
3393
-
3394
- // FIXME
3395
- // Without using map, computes the dispersion of the whole slice
3396
- // assert(x.byDim!1.dispersion == x.sliced.dispersion);
3397
- // assert(x.alongDim!0.dispersion == x.sliced.dispersion);
3398
- }
3399
-
3400
- // / Can also set functions to change type of dispersion that is used
3401
- version (mir_test)
3402
- @safe
3403
- unittest
3404
- {
3405
- import mir.ndslice.slice: sliced;
3406
- import mir.math.common: approxEqual, fabs, sqrt;
3407
- import mir.functional: naryFun;
3408
-
3409
- auto x = [0.0 , 1.0 , 1.5 , 2.0 , 3.5 , 4.25 ,
3410
- 2.0 , 7.5 , 5.0 , 1.0 , 1.5 , 0.0 ].sliced;
3411
-
3412
- alias square = naryFun! " a * a" ;
3413
-
3414
- // Other population variance examples
3415
- assert (x.dispersion.approxEqual(54.76562 / 12 ));
3416
- assert (x.dispersion! mean.approxEqual(54.76562 / 12 ));
3417
- assert (x.dispersion! (mean, square).approxEqual(54.76562 / 12 ));
3418
- assert (x.dispersion! (mean, square, mean).approxEqual(54.76562 / 12 ));
3419
-
3420
- // Population standard deviation
3421
- assert (x.dispersion! (mean, square, mean).sqrt.approxEqual(sqrt(54.76562 / 12 )));
3422
-
3423
- // Mean absolute deviation about the mean
3424
- assert (x.dispersion! (mean, fabs, mean).approxEqual(21.0 / 12 ));
3425
- // Mean absolute deviation about the median
3426
- assert (x.dispersion! (median, fabs, mean).approxEqual(19.25000 / 12 ));
3427
- // Median absolute deviation about the mean
3428
- assert (x.dispersion! (mean, fabs, median).approxEqual(1.43750 ));
3429
- // Median absolute deviation about the median
3430
- assert (x.dispersion! (median, fabs, median).approxEqual(1.25000 ));
3431
- }
3432
-
3433
- /+ +
3434
- For integral slices, pass output type to `centralTendency`, `transform`, and
3435
- `summary` functions as template parameter to ensure output type is correct.
3436
- +/
3437
- version (mir_test)
3438
- @safe pure nothrow
3439
- unittest
3440
- {
3441
- import mir.ndslice.slice: sliced;
3442
- import mir.math.common: approxEqual;
3443
- import mir.functional: naryFun;
3444
-
3445
- auto x = [0 , 1 , 1 , 2 , 4 , 4 ,
3446
- 2 , 7 , 5 , 1 , 2 , 0 ].sliced;
3447
-
3448
- alias square = naryFun! " a * a" ;
3449
-
3450
- auto y = x.dispersion;
3451
- assert (y.approxEqual(50.91667 / 12 ));
3452
- static assert (is (typeof (y) == double ));
3453
-
3454
- assert (x.dispersion! (mean! float , square, mean! float ).approxEqual(50.91667 / 12 ));
3455
- }
3456
-
3457
- /+ +
3458
- Dispersion works for complex numbers and other user-defined types (provided that
3459
- the `centralTendency`, `transform`, and `summary` functions are defined for those
3460
- types)
3461
- +/
3462
- version (mir_test)
3463
- @safe pure nothrow
3464
- unittest
3465
- {
3466
- import mir.ndslice.slice: sliced;
3467
- import mir.math.common: approxEqual;
3468
-
3469
- auto x = [1.0 + 2i, 2 + 3i, 3 + 4i, 4 + 5i].sliced;
3470
- assert (x.dispersion.approxEqual((0.0 + 10. 0i)/ 4 ));
3471
- }
3472
-
3473
- // / Compute mean tensors along specified dimention of tensors
3474
- version (mir_test)
3475
- @safe pure
3476
- unittest
3477
- {
3478
- import mir.ndslice.fuse: fuse;
3479
- import mir.algorithm.iteration: all;
3480
- import mir.math.common: approxEqual;
3481
- import mir.ndslice.topology: as, iota, alongDim, map, repeat;
3482
-
3483
- auto x = [
3484
- [0.0 , 1 , 2 ],
3485
- [3.0 , 4 , 5 ]
3486
- ].fuse;
3487
-
3488
- assert (x.dispersion.approxEqual(17.5 / 6 ));
3489
-
3490
- auto m0 = [2.25 , 2.25 , 2.25 ];
3491
- assert (x.alongDim! 0. map! dispersion.all! approxEqual(m0));
3492
- assert (x.alongDim! (- 2 ).map! dispersion.all! approxEqual(m0));
3493
-
3494
- auto m1 = [2.0 / 3 , 2.0 / 3 ];
3495
- assert (x.alongDim! 1. map! dispersion.all! approxEqual(m1));
3496
- assert (x.alongDim! (- 1 ).map! dispersion.all! approxEqual(m1));
3497
-
3498
- assert (iota(2 , 3 , 4 , 5 ).as! double .alongDim! 0. map! dispersion.all! approxEqual(repeat(1800.0 / 2 , 3 , 4 , 5 )));
3499
- }
3500
-
3501
- // / Arbitrary dispersion
3502
- version (mir_test)
3503
- @safe pure nothrow @nogc
3504
- unittest
3505
- {
3506
- import mir.math.common: approxEqual;
3507
- import mir.functional: naryFun;
3508
-
3509
- alias square = naryFun! " a * a" ;
3510
-
3511
- assert (dispersion(1.0 , 2 , 3 ).approxEqual(2.0 / 3 ));
3512
- assert (dispersion! (mean! float , square, mean! float )(1 , 2 , 3 ).approxEqual(2f / 3 ));
3513
- }
3514
-
3515
- version (mir_test)
3516
- @safe pure nothrow
3517
- unittest
3518
- {
3519
- import mir.math.common: approxEqual;
3520
- assert ([1.0 , 2 , 3 , 4 ].dispersion.approxEqual(5.0 / 4 ));
3521
- }
3522
-
3523
- version (mir_test)
3524
- @safe pure nothrow
3525
- unittest
3526
- {
3527
- import mir.ndslice.topology: iota, alongDim, map;
3528
- import mir.math.common: approxEqual;
3529
- import mir.algorithm.iteration: all;
3530
-
3531
- auto x = iota([2 , 2 ], 1 );
3532
- auto y = x.alongDim! 1. map! dispersion;
3533
- assert (y.all! approxEqual([0.25 , 0.25 ]));
3534
- static assert (is (meanType! (typeof (y)) == double ));
3535
- }
3536
-
3537
- version (mir_test)
3538
- @safe pure @nogc nothrow
3539
- unittest
3540
- {
3541
- import mir.ndslice.slice: sliced;
3542
- import mir.math.common: approxEqual;
3543
-
3544
- static immutable x = [0.0 , 1.0 , 1.5 , 2.0 , 3.5 , 4.25 ,
3545
- 2.0 , 7.5 , 5.0 , 1.0 , 1.5 , 0.0 ];
3546
-
3547
- assert (x.sliced.dispersion.approxEqual(54.76562 / 12 ));
3548
- }
3549
-
3550
3263
/+ +
3551
3264
A linear regression model with a single explanatory variable.
3552
3265
+/
0 commit comments