From ee4cd7d2b527a5ca5827c4b2f4518f7dedf6df60 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Wed, 7 Feb 2024 12:03:34 -0500 Subject: [PATCH] table: summary: omit NaNs from mean(), include NaN counts --- CHANGES.txt | 9 +++--- inst/+tblish/+internal/nanmean.m | 48 ++++++++++++++++++++++++++++++++ inst/@table/table.m | 13 ++++++--- 3 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 inst/+tblish/+internal/nanmean.m diff --git a/CHANGES.txt b/CHANGES.txt index c60a79a3..22e8be55 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,16 +4,17 @@ Tablicious Changelog Unreleased (in progress) ----------------------- -* Add `end` override methods to `string`, `datetime`, etc. so `x(end)` indexing works correctly. +* Add `end` override methods to string, datetime, etc. so `x(end)` indexing works correctly. +* table: summary: omit NaNs from mean(), include NaN counts 0.4.1 (2024-02-07) ------------------ ### Bug Fixes -* `string`: - * `string`: Fix missing trailing newline in string display in `string.disp`. - * `string`: Add `+` operator overload that does string concatenation. +* string: + * string: Fix missing trailing newline in string display in `string.disp`. + * string: Add `+` operator overload that does string concatenation. Version 0.4.0 (2024-02-07) -------------------------- diff --git a/inst/+tblish/+internal/nanmean.m b/inst/+tblish/+internal/nanmean.m new file mode 100644 index 00000000..dff9b743 --- /dev/null +++ b/inst/+tblish/+internal/nanmean.m @@ -0,0 +1,48 @@ +## Copyright (C) 2024 Andrew Janke +## +## This file is part of Tablicious. +## +## Octave is free software: you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +function out = nanmean (x, dim) + # mean, omitting NaNs + # + # This function exists so that we can do this on Octaves prior to 7.x, which did + # not support the 'omitnan'option. + # + # This is a minimal implementation that supports only the mean calculations that table + # needs. + if (ndims (x) > 2) + error ('tblish.internal.nanmean: only 2-D inputs are supported'); + endif + + if (isvector (x) && nargin == 1) + x2 = x (~isnan(x)); + out = mean (x2); + else + if (nargin < 2 || isempty (dim)); dim = 1; endif + if (dim == 1) + out = NaN (1, size (x, 2)); + for i = 1:size (x, 2) + out(i) = tblish.internal.nanmean (x(:,i)); + endfor + elseif (dim == 2) + outInv = tblish.internal.nanmean (x', 1); + out = outInv'; + else + error ('tblish.internal.nanmean: invalid dim argument: %d', dim) + endif + endif +endfunction diff --git a/inst/@table/table.m b/inst/@table/table.m index 433d6a78..b4ea07e4 100644 --- a/inst/@table/table.m +++ b/inst/@table/table.m @@ -3267,10 +3267,12 @@ function summary_impl (this, fmt) endfunction function out = summary_for_var_numeric (x) - x_min = min (x); - x_mean = mean (x); - x_max = max (x); - x_prcts = prctile (x, [25 50 75]); + xvec = x(:); + x_min = min (xvec); + x_mean = tblish.internal.nanmean (xvec); + x_max = max (xvec); + x_prcts = prctile (xvec, [25 50 75]); + n_nans = sum (isnan (xvec)); out = { 'Min.' num2str(x_min) '1st Qu.' num2str(x_prcts(1)) @@ -3279,6 +3281,9 @@ function summary_impl (this, fmt) '3rd Qu.' num2str(x_prcts(3)) 'Max.' num2str(x_max) }; + if (n_nans > 0) + out = [out; {'N. NaN', num2str(n_nans)}]; + endif endfunction function out = summary_for_var_categorical (x)