Monday, July 27, 2009

Matlab: grouping values according to ID

See also this post.

Q:

If we have n x 2 matrix x:

x = [11 19; 11 29; 10 34; 7 189; 6 123; 11 18; 21 182; 3 171; 6 145; 7 111]


Where the first column specifies the group ID and we want to break up the 2nd column into a cell array according to the grouping ID.

The desired output is:

c = {[171]; [145; 123]; [189; 111]; [34]; [18; 29; 19]; [182]}



A:

[u,dump,g] = unique(x(:,1))
c = accumarray(g,x(:,2),[length(u),1],@(x){x})

Matlab: handling nan for findstr

In many situations handling NaNs can be tricky if we want to write vectorized code.

For example, if I have vector

x = [1 2 3 nan 5 6 nan nan 9 10 11 12 nan 14]


If I want to locate 2 consequtive NaNs, I may use a combination of find, isnan, and diff.

However, what if I want to locate a subvector that also contains NaN? For instance, how to find

y = [3 nan 5]


in x?

If y does not contain NaNs, we know we can use findstr.

The straitforward solution is to convert NaNs to some value that doesn't appear in y.

For example,

sudoNan = max(x)+1;
x(isnan(x)) = sudoNan;
y(isnan(y)) = sudoNan;
findstr(x,y)


An even easier method is:

xc = typecast(x,'uint64');
yc = typecast(y,'uint64');
findstr(xc,yc)

Matlab: grouping and add up values according to ID

OP here.

Q:
Suppose I have n x 3 matrix x, I want a piece of code that checks the first and second columns and if they are equal then it adds up the correponding values in the third column.

x = [
1 2 3; 1 2 5; 1 2 3;...
1 3 1; 1 3 1; 2 1 1;...
2 1 1; 2 1 2; 2 1 2]


The desired answer should be

y = [
1 2 11; 1 3 2; 2 1 6]


A:

[val, dump, idx] = unique(x(:,1:2),'rows')
y = [val, accumarray(idx,x(:,3))]

Matlab: fast way to insert zeros into a vector

OP here.

Q:

Suppose I have vector

x = [1 2 3 4 5 6 7]

How do I insert zeros at every 3rd position to obtain

y = [1 2 0 3 4 0 5 6 0 7]

A1:
y = zeros(1,floor(length(x)*1.5));
z = 1:length(x);
y(z+ceil(z/2)-1) = x;

Matlab: indexing matrix of unknown number of dimensions

OP here.

Q:

If I know a multidimensional matrix x has 4 dims, I can index the first "row" of x using

x(1,:,:,:)


but how do I do this if I don't know ndims beforehand?

A:
c(1:ndims(x)-1)={':'};
x(1,c{:})

Matlab: counting zeros neighbouring each element

Q:

I have matrix x, I want to count for each element the number of zeros in the neighbouring 8 element.

For example, if

x = [
1 0 0
0 1 1
0 1 0];

I want to obtain count

c = [
2 2 1
2 5 3
1 3 0];

A:
c = conv2([1 1 1; 1 0 1; 1 1 1],double(~x),'same');


OR


c = conv2([1 1 1],[1 1 1],double(~x),'same')-~x;

Saturday, July 25, 2009

Matlab: optimization

OP here.

Q:
Is there a way to optimize this for loop?


f = 0;
for i = 1:n
for j = i+1:n
z = y(i) - y(j) ;
f = f + z*z ;
end
end
f = 2*f;



A1:
yy = meshgrid(y);
f = sum(sum((yy - yy.').^2));


A2:
Assuming y is column vector:

f = 2*((n+1)*sum(y.^2)-2*cumsum(y')*y);


A little bit explanation:

Suppose

y = [y1 y2 y3 y4]

f =
(y1-y2).^2 + (y1-y3).^2 + (y1-y4).^2 +
(y2-y3).^2 + (y2-y4).^2 +
(y3-y4).^2
=
y1y1+y2y2-2*y1y2 + y1y1+y3y3-2*y1y3 + y1y1+y4y4-2*y1y4 +
y2y2+y3y3-2*y2y3 + y2y2+y4y4-2*y2y4 +
y3y3+y4y4-2*y3y4
=
y1y1 + y1y1 + y1y1 +
y2y2 + y2y2 + y2y2 +
y3y3 + y3y3 + y3y3 +
y4y4 + y4y4 + y4y4 - 2*(
y1y2 + y1y3 + y1y4 + y2y3 + y2y4 + y3y4
)
=
3*sum(y.^2) - 2*(
(y1).*y2
(y1+y2).*y3
(y1+y2+y3).*y4
)