how to create an arrays from rows using Matlab - arrays

Hi guys i need your help, so i have an array
a b c n
1 1 2 4
1 3 2 6
1 6 0 7
and i want to create another array form each rows of my array, see picture below.
I tried using this code:
assuming that my data is located at array M so,
for x=1:10
d = M(:,4)/(M(:,1) + M(:,2) + M(:,3) + x)
end
but it doesn't give my desired output
in excel you just only write the equation and drag it down, in you will have the answer but i don't know how to do it in matlab, i think we could use for loop. thanks.
PLEASE SEE THE RED BOX THAT'S MY DESIRED OUTPUT

The equivalent in Matlab would be:
data = [...
1 1 2 4;
1 3 2 6;
1 6 0 7]
x = (1:10).';
f = #(t) data(t,4)./(data(t,1) + data(t,2) + data(t,3) + x )
y = [ x f(1) x f(2) x f(3) ]
or even simpler:
N = 10;
f = #(t) [(1:N).' data(t,4)./(data(t,1) + data(t,2) + data(t,3) + (1:N).' )]
y = [ f(1) f(2) f(3) ]
the number in f(...) always indicates which row, respectively which y e.g. y1, y2, etc. you are calculating for each column of the output. The brackets [...] are concatenating the result.
Be aware that you need to use the element-wise division operator ./
Generalized for an n x m sized input array, but assuming that the n-column is always the last one of your input Matrix:
N = 10;
f = #(t) [(1:N).' data(t,end)./(sum( data(t,(1:end-1))) + (1:N).' )]
y = cell2mat(arrayfun(f, 1:size(data,1),'uni',0))
But in this case you should think about, if a more vectorized approach like Divakar's answer might be more appropriate.
result:
y =
1 0.8 1 0.85714 1 0.875
2 0.66667 2 0.75 2 0.77778
3 0.57143 3 0.66667 3 0.7
4 0.5 4 0.6 4 0.63636
5 0.44444 5 0.54545 5 0.58333
6 0.4 6 0.5 6 0.53846
7 0.36364 7 0.46154 7 0.5
8 0.33333 8 0.42857 8 0.46667
9 0.30769 9 0.4 9 0.4375
10 0.28571 10 0.375 10 0.41176

Vectorized approach to get the desired output with another good case for bsxfun to have the desired output for a generic m x n sized input array -
N = 10; %// Number of rows in the output
[m,n] = size(M) %// Get size
sum_cols = sum(M(:,1:n-1),2) %// sum along dim-2 until the second last column
sum_firstN = bsxfun(#plus,sum_cols,1:N) %// For each column-sum, add 1:N
out1 = bsxfun(#ldivide,sum_firstN,M(:,n)).'%//'# elementwise divide by last col
out = [repmat([1:N]',1,n); out1] %//'# Concatenate with starting columns of 1:N
out = reshape(out,N,[]) %// Reshape into desired shape
Code run for given 3 x 4 sized input array -
out =
1.0000 0.8000 1.0000 0.8571 1.0000 0.8750
2.0000 0.6667 2.0000 0.7500 2.0000 0.7778
3.0000 0.5714 3.0000 0.6667 3.0000 0.7000
4.0000 0.5000 4.0000 0.6000 4.0000 0.6364
5.0000 0.4444 5.0000 0.5455 5.0000 0.5833
6.0000 0.4000 6.0000 0.5000 6.0000 0.5385
7.0000 0.3636 7.0000 0.4615 7.0000 0.5000
8.0000 0.3333 8.0000 0.4286 8.0000 0.4667
9.0000 0.3077 9.0000 0.4000 9.0000 0.4375
10.0000 0.2857 10.0000 0.3750 10.0000 0.4118

Related

in matlab put data into bins and calculate mean

In matlab, say I have the following data:
data = [4 0.1; 6 0.5; 3 0.8; 2 1.4; 7 1.6; 12 1.8; 9 1.9; 1 2.3; 5 2.5; 5 2.6];
I want to place the 1st column into bins according to elements in the 2nd column (i.e. 0-1, 1-2, 2-3...), and calculate the mean and 95% confidence interval of the elements in column 1 within that bin . So I'd have a matrix something like this:
mean lower_95% upper_95% bin
4.33 0
7.5 1
3.67 2
You can use accumarray with the appropriate function for the mean (mean) or the quantiles (quantile):
m = accumarray(floor(data(:,2))+1, data(:,1), [], #mean);
l = accumarray(floor(data(:,2))+1, data(:,1), [], #(x) quantile(x,.05));
u = accumarray(floor(data(:,2))+1, data(:,1), [], #(x) quantile(x,.95));
result = [m l u (0:numel(m)-1).'];
This can also be done calling accumarray once with cell array output:
result = accumarray(floor(data(:,2))+1, data(:,1), [],...
#(x) {[mean(x) quantile(x,.05) quantile(x,.95)]});
result = cell2mat(result);
For your example data,
result =
4.3333 3.0000 6.0000 0
7.5000 2.0000 12.0000 1.0000
3.6667 1.0000 5.0000 2.0000
This outputs a matrix with the labelled columns. Note that for your example data, 2 standard deviations from the mean (for the 95% confidence interval) gives values outside of the bands. With a larger (normally distributed) data set, you wouldn't see this.
Your data:
data = [4 0.1; 6 0.5; 3 0.8; 2 1.4; 7 1.6; 12 1.8; 9 1.9; 1 2.3; 5 2.5; 5 2.6];
Binning for output table:
% Initialise output matrix. Columns:
% Mean, lower 95%, upper 95%, bin left, bin right
bins = [0 1; 1 2; 2 3];
out = zeros(size(bins,1),5);
% Cycle through bins
for ii = 1:size(bins,1)
% Store logical array of which elements fit in given bin
% You may want to include edge case for "greater than or equal to" leftmost bin.
% Alternatively you could make the left bin equal to "left bin - eps" = -eps
bin = data(:,2) > bins(ii,1) & data(:,2) <= bins(ii,2);
% Calculate mean, and mean +- 2*std deviation for confidence intervals
out(ii,1) = mean(data(bin,2));
out(ii,2) = out(ii,1) - 2*std(data(bin,2));
out(ii,3) = out(ii,1) + 2*std(data(bin,2));
end
% Append bins to the matrix
out(:,4:5) = bins;
Output:
out =
0.4667 -0.2357 1.1690 0 1.0000
1.6750 1.2315 2.1185 1.0000 2.0000
2.4667 2.1612 2.7722 2.0000 3.0000

interp1 does not return expected results

I'm trying to interpolate the values of a vector but I can't seem to understand how to use interp1.m properly.
This is what I'm expecting:
a=[1 0 2 0 3 0 4];
//Use of interp1.m
Output=[1 1.5 2 2.5 3 3.5 4];
a=[1 0 0 2 0 0 3 0 0 4];
//Use of interp1.m
Output=[1 1.32 1.65 2 2.31 2.64 3 3.3 3.63 4];
Assuming you always want to fill the zero values of your vector:
a = [3 0 6 0 5 0 4]
mask = logical(a);
nvec = 1:numel(a);
a(~mask) = interp1(nvec(mask),a(mask),nvec(~mask))
a =
3.0000 4.5000 6.0000 5.5000 5.0000 4.5000 4.0000
Assuming you want to stretch your vector by a certain factor:
a = [3 6 5 4]
stretchfactor = 2;
a = interp1((1:numel(a))*stretchfactor - 1, a, 1:numel(a)*stretchfactor - 1)
a =
3.0000 4.5000 6.0000 5.5000 5.0000 4.5000 4.0000
This is how I think you meant to use interp1:
a=[1 2 3 4];
N=7; % # of points to interpolate between a(1)=1 and a(end)=4
xi=linspace(a(1),a(end),N); % the new intep x-grid
ai=interp1(1:numel(a),a,xi)
As a side note, if you just want to have linear spacing between any two values, just use linspace, for example:
linspace(1,4,10)
ans =
1.0000 1.3333 1.6667 2.0000 2.3333 2.6667 3.0000 3.3333 3.6667 4.0000
the zeros are real values that you entered, if you interpolate on them you "force" the result to pass through them...

Fast column by column array division

Suppose that M and N are two Arrays. In simplest case, M and N like this:
1 14 7 80
2 15 8 12
3 16 9 11
(3 Rows and 4 Columns)
I want to divide column 1 by All three Columns, then divide column 2 by All three Columns and then divide column 3 by All three Columns.
What is the fastest way to do it? ( Surely, using for-loop is not a good algorithm. )
EDIT:
here is my for-loop code:
idx = 1;
for i = 1 : size(N,2)
for j = 1 : size(M,2)
u(:,idx)=N(:,i) ./ M(:,j);
idx = idx + 1;
end
end
How about using bsxfun and permute
Assuming M and N are same and equal to A
out = bsxfun(#rdivide, permute(A,[1 3 2]), A)
Input:
A =
1 14 7 80
2 15 8 12
3 16 9 11
Results for your Sample Input:
out(:,:,1) =
1.0000 0.0714 0.1429 0.0125
1.0000 0.1333 0.2500 0.1667
1.0000 0.1875 0.3333 0.2727
out(:,:,2) =
14.0000 1.0000 2.0000 0.1750
7.5000 1.0000 1.8750 1.2500
5.3333 1.0000 1.7778 1.4545
out(:,:,3) =
7.0000 0.5000 1.0000 0.0875
4.0000 0.5333 1.0000 0.6667
3.0000 0.5625 1.0000 0.8182
out(:,:,4) =
80.0000 5.7143 11.4286 1.0000
6.0000 0.8000 1.5000 1.0000
3.6667 0.6875 1.2222 1.0000
If
A = [1 14 7 80
2 15 8 12
3 16 9 11]
Then
bsxfun(#ldivide, prod(A,2), A).*A
returning
ans =
0.0001 0.0250 0.0062 0.8163
0.0014 0.0781 0.0222 0.0500
0.0019 0.0539 0.0170 0.0255
So the idea is to just divide every element by ALL the other elements in that row (i.e. by the product of the row, prod(A,2)) and then just multiply back by the original number so cancel the fact that you've divided by it (i.e. the .*A at the end). So ans(2,3) above is 0.0222 which equals (8/(2*15*8*12))*8 where (2*15*8*12) is the product of row 3.
NOTE this answers the original question (i.e. the question you describe) and does NOT answer the question that your code implies

How not to repeat values in array using matlab / octave

Thanks goes out to Shai for getting my code to be much more efficient. The link to the original thread is here.
Original Thread
How can I have a loop check and stop if a number in the "array_all" array has been repeated from the "x" array.
Example:
Here's the code below:
x=[9,8,7,6,5,4,3,2,1]
array_all = bsxfun( #times, x(:), [1 .5 .25] ) %// generate for all values
eq_ = bsxfun( #eq, array_all, permute( x(:), [3 2 1] ) );
eq_ = max( eq_, [], 2 ); %// we do not care at which column of array_all x appeared
[mx firstRowToAppearIn] = max( squeeze(eq_), [], 1 );
toBePruned = 1:numel(x) > firstRowToAppearIn; %// prune elements that appear in array_all in a row preceding their location in x
pruned_array=array_all;
pruned_array(toBePruned,:) = []; %// remove those lines
st = struct();
for ii=1:size(pruned_array,1)
nm = sprintf('array_dyn_name%d',ii);
st.(nm) =pruned_array(ii,:);
end
pruned_array
fprintf('\nfinally Done-elapsed time -%4.4fsec- or -%4.4fmins- or -%4.4fhours-\n',toc,toc/60,toc/3600);
The output is:
array_all =
9.00000 4.50000 2.25000
8.00000 4.00000 2.00000
7.00000 3.50000 1.75000
6.00000 3.00000 1.50000
5.00000 2.50000 1.25000
4.00000 2.00000 1.00000
3.00000 1.50000 0.75000
2.00000 1.00000 0.50000
1.00000 0.50000 0.25000
pruned_array =
9.0000 4.5000 2.2500
8.0000 4.0000 2.0000
7.0000 3.5000 1.7500
6.0000 3.0000 1.5000
5.0000 2.5000 1.2500
We run into problems with 1.0000 0.5000 0.2500 we know it's due to the fact that it found the number 1.0000 in a previous check of the array array_all but how can we fix it?
The array we are trying to get is below:
pruned_array =
9.0000 4.5000 2.2500
8.0000 4.0000 2.0000
7.0000 3.5000 1.7500
6.0000 3.0000 1.5000
5.0000 2.5000 1.2500
1.0000 0.5000 0.2500
PS: The numbers will not be this simple there will be thousands of values. And I won't know when they will repeat.
Ps: I'm using octave 3.8.1
Using a loop
%// create the data
x=[9,8,7,6,5,4,3,2,1]
array_all = bsxfun( #times, x(:), [1 .5 .25] );
Start pruning
n = numel(x);
valid = false(n,1); %// at first, only first line is valid
valid(1) = true;
for ii=2:n, %// first line is valid by default
valid(ii) = ~any( reshape( array_all( valid, : ),[],1) == x(ii) );
end
Now leave only valid entries
array_all = array_all(valid, : );
You can try this out at ideone.

Multiply one part of Cell Array with a Scalar Matlab

I have a cell array that consits of a set of tracks like this:
<TL1x3> double
<TL1x3> double
<TL3x3> double
...
where TL stands for the track length. This value is different for each ekement, but there are always three columns: time, x coord, y coord.
From the tracking algorithm I get the x and y coord in pixels. However, I need them in nm, so I have to multiply them with a value, but only the second and third, not the first column of each element, e.g.:
0 5 6 x2 0 10 12
0.5 7 2 ---> 0.5 14 4
1 8 1 1 16 2
... ...
and this for every element of the array.
With cellfun, I have managed to change every cell of the array, but I don't know how to change only one part. Do you have any idea how to do this...?
You can do this by creating an anonymous function that calls bsxfun() and passing that to cellfun(). Assuming your input data is in the cell array inputData and the scale factor to apply is in the scalar variable scaleFactor;
scaledData = cellfun(#(X) bsxfun(#times, X, [1 scaleFactor scaleFactor]), inputData, 'UniformOutput', false);
I think this gives the results you want
Given sample input:
c={[1 2 3]; [4 5 6]; [7 8 9; 10 11 12; 13 14 15]};
Then:
xf = sparse([1 0 0; 0 2 0; 0 0 2]);
d=cellfun(#(x) x * xf, c, 'uniformoutput', false);
It might not be the most elegant nor efficient way, but converting your cell array to a matrix would simplify things for you:
A = {[0 5 6] ;
[0.5 7 2];
[1 8 1 ]}
B = cell2mat(A)
B(:,2:end) = 2*B(:,2:end)
Gives this in the command window:
A =
[1x3 double]
[1x3 double]
[1x3 double]
Before:
B =
0 5.0000 6.0000
0.5000 7.0000 2.0000
1.0000 8.0000 1.0000
After:
B =
0 10.0000 12.0000
0.5000 14.0000 4.0000
1.0000 16.0000 2.0000
You could also create a temporary cell array contanining the last 2 columns of your original cell array and then apply cellfun to it and put it back in the original. Are speed/performance an issue for you?

Resources