Fast column by column array division - arrays

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

Related

Mean of two values having the same timestamp in an array

Following my question Merge 2 vectors according their time values: If two values in an array have the same timestamp I need to combine them and use the average value. How can I realize this in an elegant way?
Here is an example:
%1st column = time; 2nd column = value
%there are two values with timestamp '6'
C = [1,34;2,34;5,68;6,2;6,3;7,45]
C =
1 34
2 34
5 68
6 2
6 3
7 45
%after processing
C_proc =
1.0000 34.0000
2.0000 34.0000
5.0000 68.0000
6.0000 2.5000
7.0000 45.0000
That's what accumarray is for:
out = accumarray(C(:,1),C(:,2),[],#mean) %// use with care, see below
If you don't want the zeros for the skipped indices, combine it with unique, which also avoids the necessary assumption of integer timestamps of the first approach:
[a,~,u] = unique(C(:,1))
out = [a accumarray(u,C(:,2),[],#mean)]
out =
1.0000 34.0000
2.0000 34.0000
5.0000 68.0000
6.0000 2.5000
7.0000 45.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...

Replace some values of one MATLAB matrix with values from another

I'm a new programmer, working in MATLAB, and I am hoping to substitute some values in one of my matrices with information from another matrix.
So, for example, supposing I have one matrix [A]:
A = [0 0 0 0 0
.5 0 .2 .8 0
1 .3 1 .1 .1
1 1 .4 1 1
1 1 1 1 1]
And another matrix B:
B = [.4 .3 .2 .1 .2]
I would like to replace the first nonzero value in A with the one in the same column in matrix B such that:
A_new = [0 0 0 0 0
.4 0 .2 .1 0
1 .3 1 .1 .2
1 1 .4 1 1
1 1 1 1 1]
There are some values between 0 and 1 that I want to keep untouched which precludes just changing everything between 0 and 1 (exclusive). I'm sure the solution will involve an if statement and possibly a for loop, but I'm not sure how to set it up. Any advice is appreciated!
Try this:
[~, row] = max(A~=0);
A(row + (0:size(A,1):numel(A)-1)) = B
How it works:
The first line produces a vector row containing the index of the first nonzero row in each column. This use of max is a "column-wise find" of sorts. Namely, max works down each column and tells you the row index of the maximum value in that column. Since each column only contains 0 or 1, there may be several maximizing (1) values; max gives the (index of) the first one.
In the second line that vector is transformed into a linear index to replace those elements of A.
Another way, though probably inefficient, is to use find and search for row and column locations that are non-zero. Once you find this, because MATLAB searches for non-zero entries column-wise, you can apply diff to the column indices and find transitions. The elements on the right-hand of the transition denote the first non-zero value for each column. Once you find these locations, get the corresponding row locations for these entries, create a new matrix A_new that is a copy of A, then change the corresponding entries to B. You'll need to use sub2ind for the assignment.
Something like this:
%// Define matrix
A = [0 0 0 0 0
.5 0 .2 .8 0
1 .3 1 .1 .1
1 1 .4 1 1
1 1 1 1 1];
%// Find non-zero entries
[row,col] = find(A);
%// Figure out the column locations that are the first non-zero for each column
ind = diff([Inf; col]) ~= 0;
%// Create a new matrix that is a copy of the old one
A_new = A;
%// Create the B vector
B = [.4 .3 .2 .1 .2];
%// Do the assignment
A_new(sub2ind(size(A), row(ind), (1:size(A,2)).')) = B;
Doing sub2ind is perhaps inefficient because there is a lot error checking done and that can slow things down. You can compute the linear indices manually by:
columns = size(A,2);
A_new((0:columns-1).'*columns + row(ind)) = B;
Running the above code, we get:
>> A
A =
0 0 0 0 0
0.5000 0 0.2000 0.8000 0
1.0000 0.3000 1.0000 0.1000 0.1000
1.0000 1.0000 0.4000 1.0000 1.0000
1.0000 1.0000 1.0000 1.0000 1.0000
>> A_new
A_new =
0 0 0 0 0
0.4000 0 0.2000 0.1000 0
1.0000 0.3000 1.0000 0.1000 0.2000
1.0000 1.0000 0.4000 1.0000 1.0000
1.0000 1.0000 1.0000 1.0000 1.0000

how to create an arrays from rows using Matlab

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

How do I replace a single value within a .m matlab file?

I have a .m file that contains a struct with some matrices:
%mymatfile.m
function [mymatrix,anothermatrix] = mymatfile;
mymatrix = [
1 2 0.0010 0.0010 0.0000 2.0000 2.0000 2.0000 1 0 1
2 3 2.0014 0.0007 0.0000 0.5000 0.5000 0.5000 0 0 1
3 4 0.0301 0.0001 4.0000 0.5000 0.5000 0.5000 1.16 0 1
4 5 0.0791 0.0450 0.0000 0.5000 0.5000 0.5000 0 0 1
5 6 1.0482 0.0233 0.0000 0.5000 0.5000 0.5000 0 0 1
5 7 7.5130 0.0467 0.0000 0.5000 0.5000 0.5000 0* 0 1
7 8 9.0161 0.0008 0.0000 0.5000 0.5000 0.5000 0 0 1
7 9 0.9070 0.2310 0.0000 0.5000 0.5000 0.5000 0 0 1
];
anothermatrix = [
2 0 0 3 0 10 0
9 0 0 3 0 10 0
%];
How do I change just the starred value (mymatrix(3,9)) and save the file, whilst retaining its structure/formatting? I need to perform the update from another matlab script.
You could save the entries of mymatrix in a text file, say mymatrix_text.
Then you make your function read that text file, i.e.
%mymatfile.m
[mymatrix,anothermatrix] = function get_my_matrices()
fid = fopen(mymatrix_text);
mymatrix = fscanf(fid, '%g ');
fclose(fid);
% anothermatrix = %% you can do the same above..
end
Now if you need to modify your matrix, you should just modify the text file -which is way easier and doesn't involve changing your .m file.
(For instance you may create another function to read mymatrix_text and change the desired values).
This approach looks more robust to me.
Substitute a number in for the old one. The fields seem to be tab delimited.
Here's how I did it in the end (note that S is the value used to update the file):
fid = fopen('mymatfile.m') % open settings file
fseek(fid,1196,-1) % set read position
Line = fgets(fid) % read in line
Refline = Line % set reference for search and replace later
Line(47:51) = S % update specific characters in the line with new setting
fclose(fid) % close file
wholefile = fileread('test.m') % read in entire file
newfiledata = strrep(wholefile,Refline,Line) % replace line
fid2 = fopen('mymatfile.m','w') % open file to write
fprintf(fid2,'%s',newfiledata) % save to file
fclose(fid2)
With help from here: [http://www.mathworks.com/matlabcentral/answers/7066].

Resources