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

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

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

Yes i realise now using the table approach and its summary isnt the best.

Thanks forvall your advice

Also, how would you do the concatenation to show the stats for another column:
tM=array2table(d);
ourstats={'Min','Max','Abs Max'}; % a list of wanted statistics
fnS=@(x)[min(x);max(x);max(abs(x))]; % define our wanted statistics as anonymous function
dz=fnS(tM.(width(tM)-1)); % compute the statistics as array instead of end-1
xtilt=fnS(tM.(width(tM)));
tS=array2table([dz,xtilt]);
tS.Properties.RowNames=ourstats
didn't work (i.e. didnt give the headings)
Var1 Var2
_________ _________
Min -0.001955 -0.000391
Max -1.1e-05 -2.2e-05
Abs Max 0.001955 0.000391
I tried this but no luck
tS.Properties.VariableNames={"dz","xtilt"}
d=randn(5); % make up some data
tM=array2table(d);
ourstats={'Min','Max','Abs Max'}; % a list of wanted statistics
fnS=@(x)[min(x);max(x);max(abs(x))]; % define our wanted statistics as anonymous function
dz=fnS(tM.(width(tM)-1)); % compute the statistics as array instead of end-1
xtilt=fnS(tM.(width(tM)));
tS=table(dz,xtilt); % individual variables/columns are listed sequentially in table()
tS.Properties.RowNames=ourstats
tS = 3x2 table
dz xtilt _________ ______ Min -1.3967 -1.026 Max -0.083213 1.2048 Abs Max 1.3967 1.2048
NOTA BENE, however. To reference more than one column at a time, it's better to revert to the alternate syntax
W=width(tM); % save for reuse
stats=fnS(tM{:,W-1:W}); % fn works for arrays, too...
tS=array2table(stats,'VariableNames',{'dz','xtilt'},'RowNames',ourstats)
tS = 3x2 table
dz xtilt _________ ______ Min -1.3967 -1.026 Max -0.083213 1.2048 Abs Max 1.3967 1.2048
Of course, if the variable names are known from somewhere else, then can use that instead of hardcoding in the names as above to be more generic code.
"didn't work (i.e. didnt give the headings)"
An array of more than one column will always have variable names Var1, Var2, ... because there are no internal names associated with individual columns for array2table to use. table with a list of variables has those available to it so the behavior is different in that regards. You can assign variable names with the named parameter as above; if the variable names are known from somewhere else, then can use that instead to be more generic code.
What happened in your assignment by using the Properties.VariableNames is not possible to diagnose without the complete session; it is valid syntax and will work if something else we can't see here didn't go wrong. An accompanying error message would prossibly identify what that something was.

Thankyou for all your excellent explanations

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)

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

Another syntax way that uses variable names with the [end-1:end] indexing
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
sampleTable(:,sampleTable.Properties.VariableNames([end-1:end]))
ans = 5x2 table
M4 M5 __ __ 8 15 14 16 20 22 21 3 2 9
This syntax is useful if one knows a given matching name or pattern of names but the position isn't necessarily fixed.
Yes, you could match patterns or use string processing functions if you operate on the variable names.
M = magic(5);
sampleTable = array2table(M, ...
VariableNames = ["ace", "king", "queen", "jack", "ten"])
sampleTable = 5x5 table
ace king queen jack ten ___ ____ _____ ____ ___ 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
namesContainA = sampleTable(:, ...
contains(sampleTable.Properties.VariableNames, 'a'))
namesContainA = 5x2 table
ace jack ___ ____ 17 8 23 14 4 20 10 21 11 2
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}
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.

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

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
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

Asked:

on 24 Apr 2025

Edited:

dpb
on 27 Apr 2025

Community Treasure Hunt

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

Start Hunting!