How do I remove column x from all variables in my workspace?

9 views (last 30 days)
I do nor understand how to loop through variale in a workspace and perform the same thing to each of them.
I a sure it is simple...
  9 Comments
John D'Errico
John D'Errico on 7 May 2020
Edited: John D'Errico on 7 May 2020
Nope. Still thinking spreadsheet. :) Instead there you have one variable, with many named fields. It becomes almost the same thing. If you want to use a struct, you might do this:
clear A
A(1).data = [1,1,1,1;2,2,2,2;3,3,3,3];
A(2).data = [1,1,1,1;2,2,2,2;3,3,3,3];
A(3).data = [1,1,1,1;2,2,2,2;3,3,3,3];
A(4).data = [1,1,NaN,1;2,2,2,2;3,3,3,3];
A
A =
1×4 struct array with fields:
data
(Note that as you wrote it, A.d had only 3 numbers in the second row. I fixed that.)
So you might choose to have one field of now a struct array. So each struct in this array has a field called data. I could loop over the structs in this array. You can always keep the list of names somewhere for future use. A cell array might be useful, at least if you will have more interesting names than what I've chosen.
datanames = {'a','b','c','d'};
Anyway, I can loop over the elements of the struct.
for i = 1:numel(A)
find(any(isnan(A(i).data),1))
end
ans =
1×0 empty double row vector
ans =
1×0 empty double row vector
ans =
1×0 empty double row vector
ans =
3
Which would tell me that column 3 of one of those arrays held a NaN in it. So at least I was able to easily loop over the multiple variables. (And I could have been better about how I wrote that loop too.) But I'm still not really using MATLAB well as an array manipulation tool. What I want to do is to treat this as a regular array if possible.
I can extract all of those data arrays like this:
A.data
ans =
1 1 1 1
2 2 2 2
3 3 3 3
ans =
1 1 1 1
2 2 2 2
3 3 3 3
ans =
1 1 1 1
2 2 2 2
3 3 3 3
ans =
1 1 NaN 1
2 2 2 2
3 3 3 3
That would be what is called a comma separated list. Still not very usable. Better is to recognize that these variables are all 3x4 arrays. So I might just catenate them all into one 3-d array. I could do that like this:
A3d = cat(3,A.data)
A3d(:,:,1) =
1 1 1 1
2 2 2 2
3 3 3 3
A3d(:,:,2) =
1 1 1 1
2 2 2 2
3 3 3 3
A3d(:,:,3) =
1 1 1 1
2 2 2 2
3 3 3 3
A3d(:,:,4) =
1 1 NaN 1
2 2 2 2
3 3 3 3
Or, when I created my struct, I might just have immediately recognized that in fact, this is just a 3-d array. So create it as such from the very beginning. Perhaps I might have done this instead:
clear A
A(:,:,1) = [1,1,1,1;2,2,2,2;3,3,3,3];
A(:,:,2) = [1,1,1,1;2,2,2,2;3,3,3,3];
A(:,:,3) = [1,1,1,1;2,2,2,2;3,3,3,3];
A(:,:,4) = [1,1,NaN,1;2,2,2,2;3,3,3,3];
After all, there really was no need to create A as a struct in the first place.
So A is one 3-dimensional array. It has 4 pages, just like A3d.
A
A(:,:,1) =
1 1 1 1
2 2 2 2
3 3 3 3
A(:,:,2) =
1 1 1 1
2 2 2 2
3 3 3 3
A(:,:,3) =
1 1 1 1
2 2 2 2
3 3 3 3
A(:,:,4) =
1 1 NaN 1
2 2 2 2
3 3 3 3
What I'm trying to do is to lead you into the idea of keeping your data in as simple and regular a form as possible. Here the simplest form is just a 3-d array. Now, we can operate on the multiple sub-arrays far more easily. For example, are there any NaNs in there?
any(isnan(A),1)
1×4×4 logical array
ans(:,:,1) =
0 0 0 0
ans(:,:,2) =
0 0 0 0
ans(:,:,3) =
0 0 0 0
ans(:,:,4) =
0 0 1 0
I can see there is at least one column that contains a NaN. That NaN falls in the 3rd column, on the 4th page of our array. We can find that information easily enough as:
[colind,pagind] = find(squeeze(any(isnan(A),1)))
colind =
3
pagind =
4
The idea is to store your data in a form that is now capable of being manipulated as one array. We can now easily enough just delete the third column of all of our data. I'll be nice, and keep all of A around, creating a new variable called B.
B = A;
B(:,colind,:) = []
B(:,:,1) =
1 1 1
2 2 2
3 3 3
B(:,:,2) =
1 1 1
2 2 2
3 3 3
B(:,:,3) =
1 1 1
2 2 2
3 3 3
B(:,:,4) =
1 1 1
2 2 2
3 3 3
No more NaNs in any column.
The point of all this is to work with arrays. Use MATLAB as the matrix and array manipulation engine it is designed to be. Once you start to do that, everything gets far simpler. Operations that previously would have taken far more work are now little more than single lines of code. And, yes, my response was lengthy, but I was trying to lead you into the way I would prefer you think, a way that will make your life simpler in the end.

Sign in to comment.

Accepted Answer

Rik
Rik on 7 May 2020
Option n_by_Walter+1:
A.a=[1,1,1,1;2,2,2,2;3,3,3,3];
A.b=[1,1,1,1;2,2,2,2;3,3,3,3];
A.c=[1,1,1,1;2,2,2,2;3,3,3,3];
A.d=[1,1,NaN,1;2,2,2,2;3,3,3,3];
data=struct2cell(A);
data=cat(3,data{:});
L=any(isnan(data),3);
col_with_NaN=any(L,1);
data(:,col_with_NaN,:)=[];
Storing into a 3D array gives you a lot of flexibility without a lot of call to complex (and sometimes slow) functions like structfun.

More Answers (1)

Walter Roberson
Walter Roberson on 7 May 2020
Option 1
out = structfun(@(F) F(:,~any(isnan(F),1)), A, 'uniform', 0);
This would be to remove columns that have at least one nan, considering the each field by itself; this could lead to fields with different number of columns. The output is a new struct with the same field names.
Option 2
col_has_no_nan = ~any(cell2mat( structfun(@(F) {any(isnan(F),2)}, A) ), 1);
out = structfun(@(F) F(:,col_has_no_nan), A, 'uniform', 0);
This checks all columns of the fields to find columns that have at least one nan in any of the fields, and then eliminates that column from all of the fields.

Categories

Find more on Structures in Help Center and File Exchange

Tags

Community Treasure Hunt

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

Start Hunting!