2

I need to create matrix in MATLAB with the following requirement. Given a vector v, for example, [1,2,2,1,3,5,1], I need to form a matrix:

[1 0 0 1 0 0 1;
 0 1 1 0 0 0 0;
 0 0 0 0 1 0 0;
 0 0 0 0 0 0 0;
 0 0 0 0 0 1 0]

i.e. the matrix's ith column contains only one non-zero element (a single 1) at row v[i]. How can I avoid a loop and do this in an efficient way?

gevang
  • 4,994
  • 25
  • 33
Qiang Li
  • 10,593
  • 21
  • 77
  • 148
  • This doesn't answer the question, but just in case you didn't realize: A single loop across the columns of your output matrix (which makes the problem trivial to solve) should be almost as efficient as a fully vectorized solution if you're only using one CPU, and will still perform very well comparatively if you have multiple CPU. A great explanation of why is [here](http://stackoverflow.com/questions/12522888/arrayfun-can-be-significantly-slower-than-an-explicit-loop-in-matlab-why) – Colin T Bowers Sep 30 '12 at 05:30

5 Answers5

4

Others are pointing out that loops are fine here. I'll point out that sparse is FAR better. Your matrix is sparse, very much so, so use the capability of sparse to solve the problem, and save a vast amount of storage in case that matrix is large.

N = 3000;
v = ceil(rand(1,3000)*3000);

tic
A = zeros(N,N);
for i = 1:N
  A(v(i),i) = 1;
end
toc
Elapsed time is 0.069082 seconds.

tic
B = sparse(v,1:N,1,N,N);
toc
Elapsed time is 0.001308 seconds.

So if the matrix is at all large, there is a huge difference in time.

How about space?

whos A B
  Name         Size                 Bytes  Class     Attributes

  A         3000x3000            72000000  double              
  B         3000x3000               72008  double    sparse    

The matrices are identical otherwise.

sum(sum(abs(A - B)))
ans =
     0

The sparse matrix takes very little space, and you can use it just like any other matrix.

Use the capabilities of MATLAB.

1

First, I have to give my standard disclaimer, that despite the commonly held notion that loops should generally be avoided in MATLAB, loops have actually become much more efficient in modern releases of MATLAB, in large part, due to the JIT accelerator. So, certainly, benchmark your code to determine if loops actually are a bottleneck.

That said, my first thought on how to approach this problem without a loop was to index into an identity matrix (as shown below).

identityMatrix = eye(max(v(:)));
result = identityMatrix(:,v);

I think that this is a nice, clean looking solution; however, I don't necessarily know that it is significantly more efficient than using a loop. As a point of comparison, I implemented the following solution using a loop:

numRows = max(v(:));
numCols = length(v);
result = zeros(numRows,numCols);

for i=1:numCols
    result(v(i),i) = 1;
end

Based on my test runs, it looks like the top (no loop) solution is generally faster for those cases where v is not very long. However, when v contains many elements (>100 for example), I was actually seeing average times where the loop solution was beating the alternative.

grungetta
  • 1,089
  • 1
  • 7
  • 8
  • @woodchips - I hadn't thought of that, but now that you point it out this does seem like the perfect use of `sparse`. Thanks for the insight. – grungetta Sep 30 '12 at 20:34
0
m = max(v);
n = length(v);
M = zeros(m, n);
M([0:(n-1)]*m + v) = 1;
Ansari
  • 8,168
  • 2
  • 23
  • 34
0
>> v =  [1,2,2,1,3,5,1];
>> a = zeros(max(v), length(v));
>> a((0 : size(a, 1) : numel(a) - 1) + v) = 1

a =

     1     0     0     1     0     0     1
     0     1     1     0     0     0     0
     0     0     0     0     1     0     0
     0     0     0     0     0     0     0
     0     0     0     0     0     1     0
Serg
  • 13,470
  • 8
  • 36
  • 47
0

This is very similar to the step required in creating a target vector in Neural Network Assignment (Week 5- Handwritten Digit Recognition from Andrew NG ML course). We had to create a vector of 10 X 1 size for a single training output say ith output of y. If the ith training output in y is 2, the vectorized ith output was [0 1 0 0 0 0 0 0 0 0]'. So, For 5000 training examples, we required 5000 vectors.

Without much ado, The code is :


>> v =  [1,2,2,1,3,5,1];
>> v_vec = (1:5)==v';
>> v_vec
v_vec =

  1  0  0  0  0
  0  1  0  0  0
  0  1  0  0  0
  1  0  0  0  0
  0  0  1  0  0
  0  0  0  0  1
  1  0  0  0  0

>> v_vec'
ans =

  1  0  0  1  0  0  1
  0  1  1  0  0  0  0
  0  0  0  0  1  0  0
  0  0  0  0  0  0  0
  0  0  0  0  0  1  0

v_vec' is the desired output. A useful link : https://www.ee.columbia.edu/~marios/matlab/Matlab%20Tricks.pdf

Bhaskar
  • 1
  • 1
  • 1