2

I need to extract every n-th column from my matrix.

For example I have a matrix:

A =
     1    23    34    53    67    45    67    45
    12    34    45    56    67    87    98    12
     1     2     3    45    56    76    87    56

And I want to extract each group of three columns, i.e. deleting every fourth. My data should be like:

X =
     1    23    34    67    45    67
    12    34    45    67    87    98
     1     2     3    56    76    87

So I would skip the 4th column, then the 8th column and so on. I know how to extract every n-th column and row but I couldn't figure out how to use that to get what I need.

Dev-iL
  • 23,742
  • 7
  • 57
  • 99
Aybars
  • 395
  • 2
  • 11

4 Answers4

4

If you want to "save" every fourth column, then the syntax would be:

toKeep = 4:4:8;
A = rand(3,8) % Insert your matrix
B = A(:,toKeep);

i.e. you assign those values to a new matrix. In your case, you want to remove them, thus you can simply assign an empty matrix to those places, which practically deletes them.

toRemove = 4:4:8; %Every fourth column
A = rand(3,8) % Insert your matrix
A(:,toRemove) = [];

EDIT 1

As Wolfie correctly notes in the comments, you can improve this a bit by writing toRemove together with A(:,toRemove) and using the end keyword such that you have:

A = rand(3,8) % Insert your matrix
A(:,4:4:end) = [];

In this case, you do not have to worry about the size of the matrix.

EDIT 2:

This approach will of course also work, for general cases without a period. The variable toRemove will just have to contain the indexes of the columns to remove, e.g.

toRemove = randperm(8,randi(5)); %Select up to 5 random columns to remove
A = rand(3,8) % Insert your matrix
A(:,toRemove) = [];

PS. If you want to keep the original matrix, A you can just assign it to B=A; first and then perform the operation on B instead.

Nicky Mattsson
  • 3,052
  • 12
  • 28
  • This could just be improved slightly by not defining `toRemove` and using `A(:,4:4:end)` - so that you don't have to know the size of `A` but go all the way to the end regardless. – Wolfie May 03 '18 at 10:57
  • Indeed, I just wanted to be explicit on the definition of the columns to keep/remove – Nicky Mattsson May 03 '18 at 10:58
2
A = rand(3,8) % Insert your matrix
n = 4; % Index of column to skip
idx = 1:size(A,2) % create indexing array
B = A(:,mod(idx,n)~=0) % logically index
A =
    0.7094    0.6797    0.1190    0.3404    0.7513    0.6991    0.5472    0.2575
    0.7547    0.6551    0.4984    0.5853    0.2551    0.8909    0.1386    0.8407
    0.2760    0.1626    0.9597    0.2238    0.5060    0.9593    0.1493    0.2543
idx =
     1     2     3     4     5     6     7     8
B =
    0.7094    0.6797    0.1190    0.7513    0.6991    0.5472
    0.7547    0.6551    0.4984    0.2551    0.8909    0.1386
    0.2760    0.1626    0.9597    0.5060    0.9593    0.1493

The idea here is that you create an index array idx, then check where division of idx by the desired n equals zero. Whenever it does, you want to skip that column. Breaking it down:

mod(idx,n) % 0 whenever idx is entirely divisible by n
mod(idx,n)==0 % finds where the zeros are
~(mod(idx,n)==0) % finds wherever the non-zeros are, i.e. the columns we want

then we can use the last one as logical index on the columns in A generating the desired output.

One-liner, because we can:

B = A(:,mod(1:size(A,2),n)~=0)
Adriaan
  • 17,741
  • 7
  • 42
  • 75
0

This is a slightly more general solution, for cases when a clear periodicity doesn't exist within the IDs of the columns to be excluded; added for completeness.


Suppose you have matrix A with N columns, and you want to exclude the columns whose IDs are in vector E, you can use the setdiff function as demonstrated below:

N = randi([30 50]);        % Generate data size
A = randi(N^2,N,N);        % Generate data
E = randperm(N,randi(10)); % Define column ids to exclude
X = A(:,setdiff(1:N,E));   % Create output

Applied to your example it would look like this:

S = size(A,2);
X = A(:, setdiff(1:S,4:4:S) ); % No need for the intermediate variable E
Dev-iL
  • 23,742
  • 7
  • 57
  • 99
0

Building the vector of column indexes is easy, you can do it by several ways. For example, if you want to skip every n-th column and there are N columns in your matrix:

I = (1:n-1).'+(0:n:N-1);

Note that the + operates along all dimensions; in older versions of Matlab, you should use bsxfun instead.

In your case, n=4 and N=8, so I is:

1    5
2    6
3    7

Then you get your matrix only with indexing:

X = A(:,I);
Bentoy13
  • 4,886
  • 1
  • 20
  • 33
  • This looks like a very difficult way to keep certain columns, which'd be achieved with `X=A; X(:,n:n:end)=[]` would do as well, as mentioned in other answers. – Adriaan May 06 '18 at 06:46
  • @Adriaan No difficulty here IMO, but it's all subjective. If I want to raise an asset of this method, I would that that you can do it in one-line in case you don't want to keep the indexes in memory. – Bentoy13 May 07 '18 at 07:08
  • Memory-wise I'm not concerned, it's more that `bsxfun` has always been a struggle to a lot of MATLAB programmers to properly understand, and now with implicit expansion it's even more magic. I'm not saying your method isn't correct, it just looks more difficult and obfuscated to keep certain columns, instead of an easy to understand indexing operation, `n:n:end`, to remove columns. (My answer's only slightly more clear imho, as `mod` is an easy to use function, Nicky's indexing one is best I'd say) – Adriaan May 07 '18 at 07:22