Remove column mean from nonzero entries of a column - matlab

Given an sparse matrix A in MATLAB and the mean for the nonzero elements in its columns m, is there anyway to subtract the nonzero elements in each column from the mean of each column and avoid looping over columns?
I am looking for efficient solutions. Using 'bsxfun' could be one solution if it is possible to use.
Thanks

You can use the second output of find to get the column indices; use those to index into m to do the subtraction; and put the results back into A using logical indexing:
A = sparse([0 0 0 0; 1 0 3 2; 2 1 0 5]); %// example data
m = [1.5 1 3 3.5]; %// vector of mean of nonzero elements of each column
m = m(:);
[~, jj, vv] = find(A);
A(logical(A)) = vv - m(jj);
Original A:
>> full(A)
ans =
0 0 0 0
1 0 3 2
2 1 0 5
Final A:
>> full(A)
ans =
0 0 0 0
-0.5000 0 0 -1.5000
0.5000 0 0 1.5000

Related

Is there a way to group matrix elements in matlab?

I am working on a problem which requires me to group array elements and average each group. For example consider the 4 x 4 matrix M,
M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;]
I want to group this into a 2 x 2 matrix, taking an average of the elements so we would get
M1 = [0.5 0.75;
0.5 0.5;]
does anyone know a way to do this?
Many thanks
You can do this using conv2, and a little indexing, like so:
>> A = conv2(M,ones(2), 'same');
>> A(1:2:end,1:2:end)/4
ans =
0.5000 0.7500
0.5000 0.5000
I think the way to go is to first split your matrix in parts using mat2cell, then apply your functions to each part and merge them to a new matrix:
>> M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;]
M =
1 0 0 1
1 0 1 1
1 1 0 1
0 0 0 1
>> T=mat2cell(M, [2 2], [2 2])
T =
2×2 cell array
{2×2 double} {2×2 double}
{2×2 double} {2×2 double}
>> M1 = cellfun(#mean, cellfun(#mean, T, 'UniformOutput', false))
M1 =
0.5000 0.7500
0.5000 0.5000
>>
You can do something like this for any rectangle, where x and y denote the size of domains that you want to average.
function M1 = get_means(M, x, y)
[rows, cols] = size(M);
if mod(rows, x) == 0 && mod(cols, y) == 0
for i = 1:y:cols
for j = 1:x:rows
M1((j+x-1)/x, (i+y-1)/y) = sum(M(j:j+x-1,i:i+y-1),'all')/(x*y);
end
end
else
error('The matrix doesn''t have compatible dimensions.')
end
end
You can loop over the grouped matrices and then calculate the mean
M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;];
n=2; % 2x2 mat
% create new matrix with means
MM = zeros(n,n);
% row counter for mean-Matrix
r=1;
% loop over matrix groups
for row=1:n:size(M,1)
c = 1; % column counter for mean-Matrix
for col=1:n:size(M,2)
MM(r,c) = mean(mean(M(row:row+n-1, col:col+n-1)));
c = c+1;
end
r = r+1;
end
Output:
MM =
0.5000 0.7500
0.5000 0.5000

Generate truth table in MatLab

I want to create a truth table in MatLab with i columns and i2 rows. For example, if i=2, then
T =
[0 0]
[1 0]
[0 1]
[1 1]
Code to do this has already been created here
This is part of a larger project, which requires i large. Efficiency is a concern. Is there more efficient code to create a truth table? Does MatLab have a built in function to do this?
Edit: Sorry about the formatting!
Something like this?
n=2;
d=[0:2^n-1].';
T=dec2bin(d,n)
T =
00
01
10
11
dec2bin will give you a character array, which you can convert to logical, if needed. There's also de2bi that gives you a numeric array directly, but you need a newer version of Matlab and the ordering of the bits is reversed.
Here's Luis Mendo's speedup, which replicates dec2bin (n and d are as above):
T=rem(floor(d*pow2(1-n:0)),2);
ndgrid is very much your friend here:
function t = truthTable(n)
dims = repmat({[false, true]}, 1, n);
[grids{1:n}] = ndgrid(dims{:});
grids = cellfun(#(g)g(:), grids, 'UniformOutput',false);
t = [grids{:}];
First you need to create grids for the number of dimensions in your truth table. Once you have those you can columnize them to get the column vectors you need and you can horizontally concatenate those column vectors to get your truth table.
I imagine the performance of this will be quite competitive.
>> truthTable(2)
ans =
0 0
1 0
0 1
1 1
>> truthTable(4)
ans =
0 0 0 0
1 0 0 0
0 1 0 0
1 1 0 0
0 0 1 0
1 0 1 0
0 1 1 0
1 1 1 0
0 0 0 1
1 0 0 1
0 1 0 1
1 1 0 1
0 0 1 1
1 0 1 1
0 1 1 1
1 1 1 1
>>
>> timeit(#() truthTable(20))
ans =
0.030922626777
EDIT: Use reshape instead of column dereferencing for further performance improvement
function t = truthTable(n)
dims = repmat({[false, true]}, 1, n);
[grids{1:n}] = ndgrid(dims{:});
grids = cellfun(#(g) reshape(g,[],1), grids, 'UniformOutput',false);
t = [grids{:}];
>> timeit(#() truthTable(20))
ans =
0.016237298777
I know this question has been dead a while, but I was wondering the same thing and found a solution I like a lot. Thought I'd share it here:
fullfact(ones(1, i) + 1) - 1

Check neighbour pixels Matlab

I have a A which is 640x1 cell. where the value of each cell A(i,1) varies from row to row, for example A(1,1) =[], while A(2,1)=[1] and A(3,1)=[1,2,3].
There is another matrix B of size 480x640, where the row_index (i) of vector A corresponds to the col_index of matrix B. While the cell value of each row in vector A corresponds to the row_index in matrix B. For example, A(2,1)=[1] this means col_2 row_1 in matrix B, while A(3,1)=[1,2,3] means col_3 rows 1,2&3 in matrix B.
What I'm trying to do is to for each non-zero value in matrix B that are referenced from vector A, I want to check whether there are at least 4 other neighbors that are also referenced from vector A. The number neighbors of each value are determined by a value N.
For example, this is a part of matrix B where all the zeros"just to clarify, as in fact they may be non-zeros" are the neighbors of pixel X when N=3:
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 X 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
As shown, because N=3, all these zeros are pixel X's neighbors. So if more than 4 neighbor pixels are found in vector A then do something e.g G=1 if not then G=0;
So if anyone could please advise. And please let me know if any more clarification is needed.
The first thing I would do is to convert your cell of indices A to a logic matrix Amat. This makes it easier to check how many neighbours are included in A.
Here is a solution that uses this conversion. I hope the comments are enough to make it understandable.
clear all
clc
nCols = 7;
nRows = 6;
N = 3; %// Number of neighbours
M = 4; %// Minimum number of wanted connections
%// Create cell of indices A
A = cell(nCols,1);
A{1} = [];
A{2} = 1;
A{3} = [1 2 3];
A{4} = [2 5];
A{5} = 3;
A{6} = [3 5];
A{7} = [1 4 6];
%// Generate radom data B
%// (There is a 50% probability for each element of B to be zero)
Bmax = 17;
B = (randi(2,nRows,nCols)-1).*(randi(Bmax,nRows,nCols));
%// Convert the cell A to a logic matrix Amat
Amat = zeros(size(B));
for ii = 1:nCols
Amat(A{ii},ii) = 1;
end
A
B
Amat
for ii = 1:nCols
for jj = A{ii}
if B(jj,ii)>0
%// Calculate neighbour indices with a lower bound of 1
%// and an upper bound of nCols or nRows
col_lim_low = max(1,ii-N);
col_lim_high = min(nCols,ii+N);
row_lim_low = max(1,jj-N);
row_lim_high = min(nRows,jj+N);
%// Get the corresponding neighbouring-matrix from Amat
A_neighbours = ...
Amat(row_lim_low:row_lim_high,col_lim_low:col_lim_high);
%// Check the number of neighbours against the wanted number M
if sum(A_neighbours(:)) > 1 + M
%# do something
fprintf('We should do something here at (%d,%d)\n',jj,ii)
end
end
end
end
The following is a printout from one run of the code.
A =
[]
[ 1]
[1x3 double]
[1x2 double]
[ 3]
[1x2 double]
[1x3 double]
B =
1 5 0 0 11 0 16
0 13 13 0 0 0 9
0 0 0 5 0 0 0
3 8 16 16 0 2 12
0 0 5 0 9 9 0
12 13 0 6 0 15 0
Amat =
0 1 1 0 0 0 1
0 0 1 1 0 0 0
0 0 1 0 1 1 0
0 0 0 0 0 0 1
0 0 0 1 0 1 0
0 0 0 0 0 0 1
We should do something here at (1,2)
We should do something here at (2,3)
We should do something here at (5,6)
We should do something here at (4,7)
Since you have a one-to-one correspondence between A and B, there is no need to work on A. B is a logical matrix (0 if not referenced in A, 1 if referenced). You can therefore apply a simple filter2 function counting the number of active neighbors within the 8 closest elements.
Here is the code
B = rand(10,10); %generate binary matrix
h = [1 1 1;1 0 1;1 1 1]; %filter to be applied
filter2(h,B,'same')>=4 & B>0 %apply filter on B, count minimum of 4 neighbors, if only B>1
EDIT
To transform a cell array B into binary presence (0=empty, 1=not empty), use of cellfunis straightforward
B = ~cellfun(#isempty,B);
And see Armo's response to your previous question for how to create B based on A.

Creating an m by n matrix of 0s and 1s from m-sized vector of column indexes

I have a m-dimensional vector of integers ranging from 1 to n. These integers are column indexes for m × n matrix.
I want to create a m × n matrix of 0s and 1s, where in m-th row there's a 1 in the column that is specified by m-th value in my vector.
Example:
% my vector (3-dimensional, values from 1 to 4):
v = [4;
1;
2];
% corresponding 3 × 4 matrix
M = [0 0 0 1;
1 0 0 0;
0 1 0 0];
Is this possible without a for-loop?
Of course, that's why they invented sparse matrices:
>> M = sparse(1:length(v),v,ones(length(v),1))
M =
(2,1) 1
(3,2) 1
(1,4) 1
which you can convert to a full matrix if you want with full:
>> full(M)
ans =
0 0 0 1
1 0 0 0
0 1 0 0
Or without sparse matrix:
>> M = zeros(max(v),length(v));
>> M(v'+[0:size(M,2)-1]*size(M,1)) = 1;
>> M = M'
M =
0 0 0 1
1 0 0 0
0 1 0 0
Transposition is used because in matlab arrays are addressed by columns
In Octave, at least as of 3.6.3, you can do this easily using broadcasting:
M = v==1:4

Creating matrix of maximum values indices in MATLAB

Using MATLAB, I have an array of values of size 8 rows x N columns. I need to create a matrix of the same size, that counts maximum values in each column and puts 1 in the cell that contains maximum value, and 0 elsewhere.
A little example. Lets assume we have an array of values D:
D =
0.0088358 0.0040346 0.40276 0.0053221
0.017503 0.011966 0.015095 0.017383
0.14337 0.38608 0.16509 0.15763
0.27546 0.25433 0.2764 0.28442
0.01629 0.0060465 0.0082339 0.0099775
0.034521 0.01196 0.016289 0.021012
0.12632 0.13339 0.11113 0.10288
0.3777 0.19219 0.005005 0.40137
Then, the output matrix for such matrix D would be:
0 0 1 0
0 0 0 0
0 1 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
1 0 0 1
Is there a way to do it without catching vector of indices from max function and then putting ones in the right place using for loop?
A one-line answer:
M = D==repmat(max(D),size(D,1),1)
or more elegantly:
M = bsxfun(#eq, D, max(D))
Update:
According to the comments, if you want to be on the safe side and catch the accidental non-unique maximums, add the following statement:
M( cumsum(M)>1 ) = false
which will ensure that in the case of multiple maximums, only the first to occur has a corresponding one in the output matrix (this is equivalent to the behavior of the max() function's returned index).
There are probably better ways to do it, my first approach is:
D = rand(8,4)
[val, sub] = max(D)
ind = sub2ind( size(D), sub, 1:4 )
res = false( size(D) )
res( ind ) = true
I have written an extension to the original problem that can handle arbitrary multidimension array and search for maximum along any specified dimension.
I used it to solve for the Nash equilibrium in game theory. Hope others will find it helpful.
A = rand([3 3 2]);
i = 1; % specify the dimension of A through which we find the maximum
% the following codes find the maximum number of each column of A
% and create a matrix M of the same size with A
% which puts 1 in the cell that contains maximum value, and 0 elsewhere.
[Amax pos] = max(A, [], i);
% pos is a now 1x3x3 matrix (the ith dimension is "shrinked" by the max function)
sub = cell(1, ndims(A));
[sub{:}] = ind2sub(size(pos), (1:length(pos(:)))');
sub{i} = pos(:);
ind = sub2ind(size(A), sub{:});
M = false(size(A));
M(ind) = true;
Example:
A(:,:,1) =
0.0292 0.4886 0.4588
0.9289 0.5785 0.9631
0.7303 0.2373 0.5468
A(:,:,2) =
0.5211 0.6241 0.3674
0.2316 0.6791 0.9880
0.4889 0.3955 0.0377
M(:,:,1) =
0 0 0
1 1 1
0 0 0
M(:,:,2) =
1 0 0
0 1 1
0 0 0