How can I use table() with a variable number of columns?

8 Ansichten (letzte 30 Tage)
Jerry Guern
Jerry Guern am 3 Jun. 2025
Kommentiert: Jerry Guern am 4 Jun. 2025
I'm making a set of tables from a 4x4x4 array, like so:
T{jj} = table(data(jj,:,1)',data(jj,:,2)',data(jj,:,3)',data(jj,:,4)','VariableNames',colName,'RowNames',rowName);
The annoying thing is, I have to change this line every time there's a different number of columns. For example, for 3 columns, the command is:
T{jj} = table(data(jj,:,1)',data(jj,:,2)',data(jj,:,3)','VariableNames',colName,'RowNames',rowName);
I know I could do a switch on the number of columns and have a case for every possible number of columns I might ever have, but is some way around that? The obvious solution of giving it the data as an array doesn't work if you want named rows and columns:
T{jj} = table(data(jj,:,:),'VariableNames',colName,'RowNames',rowName);
Error using table (line 369)
The VariableNames property must contain one name for each variable in the table.
I get the exact same error back if I use slice():
T{jj} = table(slice(data(jj,:,:)),'VariableNames',colName,'RowNames',rowName);
But it works fine without row / column names
T{jj} = table(data(jj,:,:));
Am I missing something simple, or is this maybe a design oversight?
  4 Kommentare
Stephen23
Stephen23 am 4 Jun. 2025
"I see what you're doing, the permute() sets B up so that we can say B(:,:,1) instead of squeeze(A(1,:,:))."
The code in my comment is completely tangential to the question of robustness, it just shows an alternative approach to solve this problem (sometimes posters on this forum appreciate being shown other approaches that they have not considered, or alternative ways to design their data, etc.).
Of course you can apply PERMUTE to each column separately, exactly as you did with SQUEEZE:
A = rand(2,5,4);
C{1} = array2table(permute(A(1,:,:),[2,3,1]), VariableNames="x"+(1:4));
C{2} = array2table(permute(A(2,:,:),[2,3,1]), VariableNames="x"+(1:4));
C{:}
ans = 5×4 table
x1 x2 x3 x4 _______ _______ _______ _______ 0.69712 0.24026 0.23652 0.31064 0.23611 0.66856 0.50021 0.14906 0.17603 0.15412 0.55058 0.11504 0.29684 0.98801 0.12747 0.60465 0.10538 0.20936 0.28676 0.1681
ans = 5×4 table
x1 x2 x3 x4 _______ _______ ________ ________ 0.20072 0.28959 0.79025 0.2991 0.14334 0.61453 0.3802 0.091008 0.48252 0.31495 0.62297 0.14665 0.93305 0.13457 0.9636 0.41809 0.49103 0.89416 0.086166 0.39347
A(2,:,1).' % for comparison: the first column of the second table
ans = 5×1
0.20072 0.14334 0.48252 0.93305 0.49103
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
"But I'm not clear on why that's more "robust"... What does it buy us?"
PERMUTE buys you the guarantee that input dimensions will end up being permuted into the dimensions that are specified, which SQUEEZE does not. Consider the code you showed in your comment here:
What happens one day the input data just happens to have only one column? Lets try it:
A = rand(2,1,4);
array2table(permute(A(1,:,:),[2,3,1]), VariableNames="x"+(1:4)) % PERMUTE -> robust
ans = 1×4 table
x1 x2 x3 x4 _______ ________ _______ _______ 0.20227 0.026228 0.71921 0.72629
array2table(squeeze(A(1,:,:)), VariableNames="x"+(1:4)) % SQUEEZE -> error
Error using array2table (line 57)
The VariableNames property must contain one name for each variable in the table.
Jerry Guern
Jerry Guern am 4 Jun. 2025
Aah, okay, THAT's what you meant by robust. Thanks. I'd never actually even used squeeze() before this week, so while I knew it fixed today's problem, I didn't realize what kinds of problems my code was setting up for me. I appreciate the follow-up explanation.

Melden Sie sich an, um zu kommentieren.

Akzeptierte Antwort

Star Strider
Star Strider am 3 Jun. 2025
Something like this seems to work --
data = randn(2,5,4);
jj = 1;
T{jj} = array2table(squeeze(data(jj,:,1:3)), VariableNames=compose('Variable %2d',1:3));
jj = 2;
T{jj} = array2table(squeeze(data(jj,:,1:4)), VariableNames=compose('Variable %2d',1:4));
T{1}
ans = 5×3 table
Variable 1 Variable 2 Variable 3 ___________ ___________ ___________ -1.0069 -0.30554 -1.3129 -0.66706 0.97513 -0.12746 0.80276 0.37576 0.6067 0.64226 0.72238 0.10441 1.8353 -0.31753 -1.7157
T{2}
ans = 5×4 table
Variable 1 Variable 2 Variable 3 Variable 4 ___________ ___________ ___________ ___________ 0.3082 -0.7056 1.8303 0.44942 2.7611 1.4362 0.74181 0.76498 -2.2185 1.243 -0.15949 0.31181 -0.078775 0.56237 0.16815 -0.75866 0.30191 0.67109 0.17018 0.53208
.
  2 Kommentare
Jerry Guern
Jerry Guern am 3 Jun. 2025
This works! Thank you.
Here was the syntax that worked for my case:
T{jj} = array2table(squeeze(data(jj,:,:)),VariableNames=colName,RowNames=rowName);
Star Strider
Star Strider am 3 Jun. 2025
As always, my pleasure!

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (2)

the cyclist
the cyclist am 3 Jun. 2025
I assume that data, colName, and rowName are consistently dimensioned.
slice = squeeze(data(jj,:,:));
TT{jj} = array2table( slice,'VariableNames',colName,'RowNames',rowName);
  4 Kommentare
the cyclist
the cyclist am 3 Jun. 2025
Hm. This worked for me (and gave the same result as your syntax).
rng default
N = 4;
data = rand(N,N,N);
jj = 1;
colName = {'c1','c2','c3','c4'};
rowName = {'r1','r2','r3','r4'};
slice = squeeze(data(jj,:,:)); % this becomes an [nRows × nVars] matrix
TT{jj} = array2table( slice, ...
'VariableNames', colName, ...
'RowNames', rowName )
TT = 1×1 cell array
{4×4 table}
Image Analyst
Image Analyst am 4 Jun. 2025
@Jerry Guern, perhaps this will clear things up:
% Get last dimension.
data = randn(4,4,4); % Create a 3-D array
slice1 = data(:, :, 1); % A 2-D array
whos slice1
Name Size Bytes Class Attributes slice1 4x4 128 double
% Get middle dimension.
array2 = data(:, 1, :); % A 3-D array
whos array2
Name Size Bytes Class Attributes array2 4x1x4 128 double
slice2 = squeeze(array2); % Collapse singleton dimension to make it a 2-D slice
whos slice2
Name Size Bytes Class Attributes slice2 4x4 128 double
% Get first dimension.
array3 = data(1, :, :); % A 3-D array
whos array3
Name Size Bytes Class Attributes array3 1x4x4 128 double
slice3 = squeeze(array3); % Collapse singleton dimension to make it a 2-D slice
whos slice3
Name Size Bytes Class Attributes slice3 4x4 128 double

Melden Sie sich an, um zu kommentieren.


Image Analyst
Image Analyst am 3 Jun. 2025
Yes, you're going to have to do something. If you have more variables that you want to add to a column or columns you want to remove, it won't telepathically know that you want to do it unless you tell it, and tell it how, so you're going to have to do something. Either make up the table brand new, or use functions to change the number of columns.
Try using addvars, removevars, and movevars - maybe they'll be easier for you. Maybe make up just one column and add the others in a loop with addvars until they're all added. Unless you have a very small amount like 2-4 columns it's easier to use a for loop than an if-else block to form the exact table you want.
  2 Kommentare
Jerry Guern
Jerry Guern am 3 Jun. 2025
Well, I wasn't it expecting it to be telepathic, but I thought it might have been able to note the number of rows and columns in the first argument. In fact, I pointed out at the end that it does exactly that if you don't try to include row/col names.
Image Analyst
Image Analyst am 4 Jun. 2025
OK, from your initial post and the other posts, I guess I misunderstood, thinking you wanted a table, but it appears you actually want a cell array with tables inside the cells.

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Multidimensional Arrays finden Sie in Help Center und File Exchange

Tags

Produkte


Version

R2024a

Community Treasure Hunt

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

Start Hunting!

Translated by