Using Summary on a table to access just the last 2 column stats

18 views (last 30 days)
Hello, I have an array of numbers that I want to apply the "summary" feature associated with tables to. This is because I want to exploit the stats this gives
The issue Im having is that the number of cloumns and clomn names isnt always the same. what is the same is I really want the stats for the last 2 columns always
This is what I have done so far:
T=app.UITable;
d=T.Data;
cn=T.ColumnName
d2=array2table(d,'VariableNames',cn)
% d2.Properties
S=summary(d2)
% B = string(fieldnames(S))
% B(end)
But is is just a struct, so I wanted to access the last 2 column details which I understand is via
S.fieldname.
But thats my issue, the field name is in cn but doing
S.cn(end)
doesn't work

Accepted Answer

dpb
dpb on 25 Apr 2025
Edited: dpb on 25 Apr 2025
You fell into a trap of using a routine that isn't suitable for your purposes...while summary does compute a bunch of statistics without much need for user input, its output wasn't designed to return those parameters for other than viewing.
For your purposes I'd suggest doing something more on the line of
tM=array2table(magic(5)); % out friendly sample dataset yet again...
format bank, format compact % just to make output consistent...
% our supporting and engine code...
ourstats={'Min','Max','Mean','Median','StD'}; % a list of wanted statistics
fnS=@(x)[min(x);max(x);mean(x);median(x);std(x)]; % define our wanted statistics as anonymous function
Statistics=fnS(tM.(width(tM)-1)); % compute the statistics as array
tS=array2table(Statistics); % convert to table
tS.Properties.RowNames=ourstats % add the identifier of which is which
tS = 5x1 table
Statistics __________ Min 2.00 Max 21.00 Mean 13.00 Median 14.00 StD 8.06
The statistic names can be augmented as desired or the variable identified as the column header, your choice. It's also straightforward to add the units column.
I haven't messed with the uitable enough to know about all the internal formatting it supports although I know there is quite a bit for presentation-only purposes available, but building the base data is pretty straightforward from a "deadahead" path rather than trying to parse a difficult-to-use builtin function output.
Probably you didn't recognize that can build an anonymous function comprising several of the builtin functions outputs catenated as long as they all reduce to a common data type.
NOTA BENE:
Statistics=fnS(tM.(width(tM)-1));
is yet another addressing mode of using the desired column number. width()-1 is the same as the subscripting expression end-1 without needing the array reference for the end function to key against.
  6 Comments
dpb
dpb on 26 Apr 2025
Edited: dpb on 27 Apr 2025
Glad to help...the table(*) and all its possible addressing rules can get pretty complex; it takes some "time in grade" and a lot of study/practice to learn one's way around thoroughly.
(*) As is also the struct

Sign in to comment.

More Answers (2)

Steven Lord
Steven Lord on 24 Apr 2025
As shown on this documentation page, one of the ways to extract a sub-table from a table is numeric indices.
M = magic(5);
sampleTable = array2table(M)
sampleTable = 5x5 table
M1 M2 M3 M4 M5 __ __ __ __ __ 17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9
I could use variable names:
subtable1 = sampleTable(:, ["M4", "M5"])
subtable1 = 5x2 table
M4 M5 __ __ 8 15 14 16 20 22 21 3 2 9
Or I could use numbers.
subtable2 = sampleTable(:, [4 5])
subtable2 = 5x2 table
M4 M5 __ __ 8 15 14 16 20 22 21 3 2 9
Using end in the indexing expression also works.
subtable3 = sampleTable(:, [end-1 end])
subtable3 = 5x2 table
M4 M5 __ __ 8 15 14 16 20 22 21 3 2 9
  4 Comments
Jason
Jason on 24 Apr 2025
Thanks Steven.
but i need to get the stats and for that i need s.fieldname.
I don't know in advance what the column headings are (= the field names), but I can get it via
T=app.UITable3;
cn=T.ColumnName
So is there a way to use the S.fieldname by just getting the last field name from cn, somehting like
S=summary(d2)
stats_I_want=S.cn{end}
Steven Lord
Steven Lord on 24 Apr 2025
You could use indexing or dynamic {field, variable, property} names, depending on whether S is a {struct, table, object}.
M = magic(5);
sampleTable = array2table(M)
sampleTable = 5x5 table
M1 M2 M3 M4 M5 __ __ __ __ __ 17 24 1 8 15 23 5 7 14 16 4 6 13 20 22 10 12 19 21 3 11 18 25 2 9
n = randi(width(M), 1)
n = 5
varname = "M"+n
varname = "M5"
S1 = sampleTable.(varname) % double vector
S1 = 5×1
15 16 22 3 9
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
S2 = sampleTable(:, varname) % table
S2 = 5x1 table
M5 __ 15 16 22 3 9
S3 = sampleTable{:, varname} % double vector
S3 = 5×1
15 16 22 3 9
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>

Sign in to comment.


dpb
dpb on 24 Apr 2025
Edited: dpb on 24 Apr 2025
Use the previous illustrated syntax on the summary table, too...you said you knew the columns of interest are the last two, so
tM=array2table(magic(5));
S=summary(tM(:, [end-1 end]))
S = struct with fields:
Var4: [1x1 struct] Var5: [1x1 struct]
S.Var4
ans = struct with fields:
Size: [5 1] Type: 'double' Description: '' Units: '' Continuity: [] NumMissing: 0 Min: 2 Median: 14 Max: 21 Mean: 13 Std: 8.0623
fnames=fieldnames(S)
fnames = 2x1 cell array
{'Var4'} {'Var5'}
stats_I_want=S.(char(fnames(end)))
stats_I_want = struct with fields:
Size: [5 1] Type: 'double' Description: '' Units: '' Continuity: [] NumMissing: 0 Min: 3 Median: 15 Max: 22 Mean: 13 Std: 7.2457
It might be more simpler to use groupsummary:here depending on just what you are looking for even though may have to create a fake grouping variable...
tM1=tM(:, [end-1 end]);
tM1=addvars(tM1,ones(height(tM1),1),'NewVariableNames','Group','Before',tM1.Properties.VariableNames(1))
tM1 = 5x3 table
Group Var4 Var5 _____ ____ ____ 1 8 15 1 14 16 1 20 22 1 21 3 1 2 9
S=groupsummary(tM1,'Group','all',tM1.Properties.VariableNames(end))
S = 1x14 table
Group GroupCount mean_Var5 sum_Var5 min_Var5 max_Var5 range_Var5 median_Var5 mode_Var5 var_Var5 std_Var5 nummissing_Var5 nnz_Var5 numunique_Var5 _____ __________ _________ ________ ________ ________ __________ ___________ _________ ________ ________ _______________ ________ ______________ 1 5 13 65 3 22 19 15 3 52.5 7.2457 0 5 5
You can select any subset of the above and/or add others as well...
Alternatively, with it you can select which variables to use as the data variables as input rather than subselecting another table...
datavars=false(1,width(tM)); datavars(end)=true; % select only last variable
tM=addvars(tM,ones(height(tM),1),'NewVariableNames','Group','Before',1)
tM = 5x6 table
Group Var1 Var2 Var3 Var4 Var5 _____ ____ ____ ____ ____ ____ 1 17 24 1 8 15 1 23 5 7 14 16 1 4 6 13 20 22 1 10 12 19 21 3 1 11 18 25 2 9
S=groupsummary(tM,'Group','all',datavars)
S = 1x14 table
Group GroupCount mean_Var4 sum_Var4 min_Var4 max_Var4 range_Var4 median_Var4 mode_Var4 var_Var4 std_Var4 nummissing_Var4 nnz_Var4 numunique_Var4 _____ __________ _________ ________ ________ ________ __________ ___________ _________ ________ ________ _______________ ________ ______________ 1 5 13 65 2 21 19 14 2 65 8.0623 0 5 5
  2 Comments
Jason
Jason on 25 Apr 2025
Edited: Jason on 25 Apr 2025
Thankyou, this is exactly what I was looking for to get the last fieldname (=column heading in uitable) when it could be anything. I'd also like to appreciate Stevens effort too which has helped me.
stats_I_want=S.(char(fnames(end)))
Could I ask one more request.
I'd like to display (for the last two columns only), a table in a uitextarea showing the stats
I use this:
% Table approach
T=app.UITable3;
d=T.Data;
cn=T.ColumnName;
d2=array2table(d,'VariableNames',cn); % ,'VariableNames',{'Feet','Inches','Centimeters'}))
S=summary(d2)
fnames=fieldnames(S)
S2=S.(char(fnames(end)))
S3=S.(char(fnames(end-1)))
str = formattedDisplayText(S2) %My add to message area function, see below
where
function ReportMessage(app,msg)
currString=get(app.MessagesTextArea,'Value');
%currString=[{char(msg)};currString]; %add to top of message box
currString=[currString; {char(msg)}]; %add to bottom of message box
app.MessagesTextArea.Value=currString;
drawnow;
scroll(app.MessagesTextArea,'bottom');
end
This displays this in my textarea
Size: [667 1]
Type: 'double'
Description: ''
Units: ''
Continuity: []
NumMissing: 0
Min: -0.000391
Median: -0.000235
Max: -2.2e-05
Mean: -0.00021689
Std: 0.00013186
1: How can I just show these parameters, and justify it like this:
% column heading #1 (=end) column heading #2 (=end-1) (underlined)
Min: -0.000391 % values for this column
Median: -0.000235 % values for this column
Max: -2.2e-05 % values for this column
Mean: -0.00021689 % values for this column
Std: 0.00013186 % values for this column
This is why I used the "table approach" because i thought I could just splat the ouptut of the table summary into the uiarea with a "table" appearance
Jason
Jason on 25 Apr 2025
This seems to work:
T=app.UITable;
d=T.Data;
Mx=max(d); % Gets max of all columns by default
Mn=min(d); % Gets min of all columns by default
% Create Table manually
params = ["Max_Xtilt";"Min_Xtilt";"Max_dx(um)";"Min_dz(um)"];
Vals = [10^6*Mx(1,end);10^6*Mn(1,end);10^6*Mx(1,end-1);10^6*Mn(1,end-1)];
units = ["urads";"urads";"um";"um"];
tbl = table(params,Vals,units)
str = formattedDisplayText(tbl)
str = regexprep(str,'</?strong>','')
ReportMessage(app,str)
params Vals units
____________ _____ _______
"Max_Xtilt" -22 "urads"
"Min_Xtilt" -391 "urads"
"Max_dx(um)" -11 "um"
"Min_dz(um)" -1955 "um"

Sign in to comment.

Products


Release

R2024b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!