replacing values of a matrix with an if operation using matlab - matlab

mn = 1
for kn = 1:199
for sn = 1:19773
if abs((x1c{kn+1,1}(sn)) - (x1c{kn,1}(sn))) >= 20
extract{mn} = x1c{kn+1,1}(sn);
mn = mn+1;
end
end
end
extend = cell2mat(extract) + 40;
How can I change the values of "x1c" with the values of "extend"?

You are performing the operation on a cell. Considering you're comparing numbers, this would be done far more efficiently when done with matrices.
I therefor suggest you convert the cell (or a subset of it) to a matrix and then use vectorized operations, like this:
>> a={[13, 2, 3], [14, 25, 8], [100, 9, 10], [101, 8, 32], [140, 20, 3]};
>>
>> x = transpose(reshape(cell2mat(a), 3, []));
>> z = abs(x(2:end, :) - x(1:end-1,:)) > 20;
>> z2 = [zeros(1,3); z]
z2 =
0 0 0
0 1 0
1 0 0
0 0 1
1 0 1
>> x(logical(z2)) = x(logical(z2)) - 200
x =
13 2 3
14 -175 8
-100 9 10
101 8 -168
-60 20 -197
There are two alternatives if you really must use cells (I don't recommend it for speed reasons).
store the indices (k, sn) of the cell items where your condition holds true. And then you'd have to loop over the elements again (very inefficient).
You'd store the previous and next cell "row" in temporary variables and compare using those. When the condition holds, edit in-place and take the temporary variable with you in the next iteration of the loop. The code below shows how this is done:
a={[13, 2, 3], [14, 25, 8], [100, 9, 10], [101, 8, 32], [140, 20, 3]};
curr_row = a{1};
for rowind=1:4
next_row = a{rowind+1};
for colind=1:3
if abs(next_row(1, colind) - curr_row(1, colind)) > 20
a{rowind+1}(1, colind) = a{rowind+1}(1, colind) + 40;
end
end
curr_row = next_row;
end

Related

Sort 2 arrays/vectors based off 1 vector

I have 2 arrays (vectors? in m vernacular?) and I want to sort them in unison. How can I achieve this in Matlab?
For example; I have found the peaks from a histogram and they are stored in 2 arrays; peakXVals, peakYVals. They will always be arranged in ascending x axis index. So they will always look like:
peakXVals = [0, 3, 20, 77, 240];
peakYVals = [10, 999, 30, 40, 20];
I wish to sort both arrays based of the values in peakYVals in descending order. Ie from largest peak to smallest peak. So the desired result is:
peakXVals = [3, 77, 20, 240, 0];
peakYVals = [999, 40, 30, 20, 10];
What function's can I use to achieve this in Matlab?
Use sort:
peakXVals = [0, 3, 20, 77, 240];
peakYVals = [10, 999, 30, 40, 20];
>> [B,I] = sort(peakYVals, 'descend')
B =
999 40 30 20 10
I =
2 4 3 5 1
Then:
>> peakXVals_sorted = peakXVals(I)
peakXVals_sorted =
3 77 20 240 0
>> peakYVals_sorted = B
peakYVals_sorted =
999 40 30 20 10
You can arrange the two vectors as columns of a matrix and sort the rows of that matrix as atoms, in lexicographical order. Then the results are the columns of the sorted matrix:
tmp = sortrows([peakYVals(:) peakXVals(:)], 'descend');
peakYVals = tmp(:,1).';
peakXVals = tmp(:,2).';

Feature mapping using multi-variable polynomial

Consider we have a data-matrix of data points and we are interested to map those data points into a higher dimensional feature space. We can do this by using d-degree polynomials. Thus for a sequence of data points the new data-matrix is
I have studied a relevant script (Andrew Ng. online course) that make such a transform for 2-dimensional data points to a higher feature space. However, I could not figure out a way to generalize in arbitrary higher dimensional samples, . Here is the code:
d = 6;
m = size(D,1);
new = ones(m);
for k = 1:d
for l = 0:k
new(:, end+1) = (x1.^(k-l)).*(x2.^l);
end
end
Can we vectorize this code? Also given a data-matrix could you please suggest a way on how we can transform data points of arbitrary dimension to a higher one using a d-dimensional polynomial?
PS: A generalization of d-dimensional data points would be very helpful.
This solution can handle k variables and generate all the terms of a degree d polynomial where k and d are non-negative integers. Most of the code length is due to the combinatoric complexity of generating all the terms of a degree d polynomial in k variables.
It takes an n_obs by k data matrix X where n_obs is the number of observations and k is the number of variables.
Helper function
This function generates all possible rows such that every entry is a non-negative integer and the row sums to a positive integer:
the row [0, 1, 3, 0, 1] corresponds to (x1^0)*(x1^1)*(x2^3)*(x4^0)*(x5^1)
The function (which almost certainly could be written more efficiently) is:
function result = mg_sums(n_numbers, d)
if(n_numbers<=1)
result = d;
else
result = zeros(0, n_numbers);
for(i = d:-1:0)
rc = mg_sums(n_numbers - 1, d - i);
result = [result; i * ones(size(rc,1), 1), rc];
end
end
Initialization code
n_obs = 1000; % number observations
n_vars = 3; % number of variables
max_degree = 4; % order of polynomial
X = rand(n_obs, n_vars); % generate random, strictly positive data
stacked = zeros(0, n_vars); %this will collect all the coefficients...
for(d = 1:max_degree) % for degree 1 polynomial to degree 'order'
stacked = [stacked; mg_sums(n_vars, d)];
end
Final Step: Method 1
newX = zeros(size(X,1), size(stacked,1));
for(i = 1:size(stacked,1))
accumulator = ones(n_obs, 1);
for(j = 1:n_vars)
accumulator = accumulator .* X(:,j).^stacked(i,j);
end
newX(:,i) = accumulator;
end
Use either method 1 or method 2.
Final Step: Method 2 (requires all data in data matrix X is strictly positive (The problem is that if you have 0 elements, the -inf doesn't propagate properly when you call the matrix algebra routines.)
newX = real(exp(log(X) * stacked')); % multiplying log of data matrix by the
% matrix of all possible exponent combinations
% effectively raises terms to powers and multiplies them!
Example Run
X = [2, 3, 5];
max_degree = 3;
The stacked matrix and the polynomial term it represents are:
1 0 0 x1 2
0 1 0 x2 3
0 0 1 x3 5
2 0 0 x1.^2 4
1 1 0 x1.*x2 6
1 0 1 x1.*x3 10
0 2 0 x2.^2 9
0 1 1 x2.*x3 15
0 0 2 x3.^2 25
3 0 0 x1.^3 8
2 1 0 x1.^2.*x2 12
2 0 1 x1.^2.*x3 20
1 2 0 x1.*x2.^2 18
1 1 1 x1.*x2.*x3 30
1 0 2 x1.*x3.^2 50
0 3 0 x2.^3 27
0 2 1 x2.^2.*x3 45
0 1 2 x2.*x3.^2 75
0 0 3 x3.^3 125
If data matrix X is [2, 3, 5] this correctly generates:
newX = [2, 3, 5, 4, 6, 10, 9, 15, 25, 8, 12, 20, 18, 30, 50, 27, 45, 75, 125];
Where the 1st column is x1, 2nd is x2, 3rd is x3, 4th is x1.^2, 5th is x1.*x2 etc...

How to separate combinatorics in a loop?

Lets say I have 4 locations, x = rand(4,1). For each location I would like to calculate the distance to each of the other 3 locations, d = pdist(x, 'euclidean'). This gives me 6 unique distances, eg. 12, 13, 14, 23, 24, 34.
How do I separate these combinations, such that I get all distances from respective location 1, 2, 3 to the others. So the results should look like:
[1 2 3]
[4 5]
[6]
Maybe squareform is what you're after. It unpacks all distances into a square, symmetric matrix:
>> x = rand(4,1)
x =
0.5290
0.5673
0.4487
0.9872
>> d = pdist(x, 'euclidean')
d =
0.0383 0.0802 0.4582 0.1186 0.4199 0.5384
>> D = squareform(d)
D =
0 0.0383 0.0802 0.4582
0.0383 0 0.1186 0.4199
0.0802 0.1186 0 0.5384
0.4582 0.4199 0.5384 0
so for example D(2,3) (or D(3,2)) is the distance from point 2 to point 3.
Create an index with all the 6 combinations, idx = [1 2 3 4 5 6]. Remove respectively the first 3, 2, 1 elements in this index for each loop (idx(1:Num-n) = []).
Num = 4;
idx = 1:nchoosek(Num,2); % index of all combinations
for n = 1:Num-1 % loop through all except last
idx(1:Num-n) % print
idx(1:Num-n) = []; % remove the first elements in index
end
This will give the following result
ans = 1 2 3
ans = 4 5
ans = 6

MatLab - histc with many edges vector

Consider this :
a = [1 ; 7 ; 13];
edges = [1, 3, 6, 9, 12, 15];
[~, bins] = histc(a, edges)
bins =
1
3
5
Now I would like to have the same output, but with a different "edges" vector for each a value, i.e. a matrix instead of a vector for edges. Exemple :
a = [1 ; 7 ; 13];
edges = [ 1, 3, 6 ; 1, 4, 15 ; 1, 20, 30];
edges =
1 3 6
1 4 15
1 20 30
indexes = theFunctionINeed(a, edges);
indexes =
1 % 1 inside [1, 3, 6]
2 % 7 indide [1, 4, 15]
1 %13 inside [1, 20, 30]
I could do this with histc inside a for loop, by I'm trying to avoid loops.
If you transform your arrays to cell arrays, you can try
a = {1 ; 7 ; 13};
edges = {[ 1, 3, 6 ];[ 1, 4, 15] ; [1, 20, 30]};
[~, indexes] = cellfun(#histc, a, edges,'uniformoutput', false)
This results in
indexes =
[1]
[2]
[1]
~edit~
To transform your matrices into cell arrays you can use num2cell:
a = num2cell(a);
edges = num2cell(edges, 2);
You could also do:
a = [1; 7; 13];
edges = [1 3 6; 1 4 15; 1 20 30];
bins = sum(bsxfun(#ge, a, edges), 2)
The result:
>> bins
bins =
1
2
1

matlab - cellfun sum all elements of each cell

Hi I have populated a cell array using:
D(i) = {dist};
D = reshape(D, w, h)
so that if i have:
pix1 = D{1,1};
pix2 = D{2,2};
I get
pix1 =
1 2 3
pix2 =
4 5 6
What I want to do is sum all the elements in each pix, and then take those results and form a matrix i.e.
sum(pix1) = 6
sum(pix2) = 15
matrix =
6 15
where in this case matrix is a 1X2 matrix (mine is a lot larger).
I am trying to do this using:
field = cellfun(#(dist) sum(dist(:)), D,'UniformOutput', false);
but this just gives me a matrix full of NaN's. Where am I going wrong?
A = {[1 2 4], [4 5 6]};
B = cellfun(#sum, A)
results in
B = [6 15]
B = [7 15]
In case you have NaNs in your cells and you wish to ignore them you may use nansum:
A = {[1, 2, NaN], [3, NaN, 4, 5]; [6, NaN], [10, -3, NaN, 4]};
B = cellfun( #nansum, A )
Results with
B =
3 12
6 11