Replace some values of one MATLAB matrix with values from another - arrays

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

Related

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 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 to make value in excel sheet become element of matrix in matlab

i have xls file name databus.xls, like this
No. Bus Code Voltage Mag. Fasa Beban Generator Stat Mvar
MW Mvar MW Mvar Qmin Qmax +Qc/-Ql'
1 1 1.04 0 50 30.99 0 0 0 0 0
2 0 1 0 170 105.35 0 0 0 0 0
3 0 1 0 200 123.94 0 0 0 0 20
4 2 1.02 0 80 49.58 318 0 0 0 0
how to make the value become component of matrix a
like
a=[1 1 1.04 0 50 30.99 ...etc
2 0 1 0 170 105.35 ...etc
...etc ]
If this is a one time operation, copy-paste is the simplest approach. If not, I would suggest xlsread
Try:
filename = 'databus.xls';
sheet = 1;
xlRange = 'A3:J7';
a = xlsread(filename, sheet, xlRange)
If there's only one sheet, you can skip the second argument and just do:
filename = 'databus.xls';
a = xlsread(filename,'A3:J7')
If you do not know the range, simply follow the documentation given in the link above:
num = xlsread(filename) reads data from the first worksheet in the
Microsoft® Excel® spreadsheet file named filename and returns the
numeric data in array num.
So, to show an example:
num = xlsread('test.xlsx')
num =
1.0000 1.0000 1.0000 50.0000 30.0000
2.0000 1.0000 1.0000 112.0000 60.0000
3.0000 2.0000 4.0000 40.0000 20.0000
4.0000 2.0000 3.0000 30.0000 20.0000
5.0000 3.0000 2.0000 60.0000 42.5000
As this reads all numeric data, you might get some rows with mostly NANs, if only a few of the columns contain numbers. If that's the case, you can simply delete those lines.
You have to split your task in two:
Export your data from Excel.
Import your data into Matlab.
For task 2, there are several options (links to official documentation are provided):
csvread
dimread
fscanf
importdata
Etc.?
See also Ways to Import Text Files and How do you create a matrix from a text file in MATLAB?.
If you use method 1 for task 2, then you have to export as csv from Excel.
Copy your worksheet into a new one.
Remove data not going into your matrix (as per your question, the first two rows).
Save as CSV.
Voilà

First N values of a function with two inputs

I have a function with two integer inputs like this:
function f = func(n, m)
a = 2;
b = 1;
f = sqrt((n/a)^2 + (m/b)^2);
end
m and n are integers and greater than or equal to zero. The first couple of values of f and the inputs they occure in are like below:
n ----- m ----- f
0 ----- 0 ----- 0
1 ----- 0 ----- 0.5
2 ----- 0 ----- 1
0 ----- 1 ----- 1
1 ----- 1 ----- 1.118
and so on. I want to get the first N values of f and their respective n and m. Is there an easy way to do that in matlab?
Code
%// Parameters
N = 5
a = 2;
b = 1;
%// Extents of n and m would be from 0 to N-1 to account for all possible
%// minimum values of f results resulting from their use
len1 = N-1
%// Create n and m for maximum possible combinations scenario, but save
%// them as n1 and m1 for now, as the final ones would be chopped versions
%// of them.
[n1,m1] = ndgrid(0:len1,0:len1)
%// Get corresponding f values, but store as f1, for the same chopping reason
f1 = sqrt((n1(:)./a).^2 + (m1(:)./b).^2);
%// Sort f1 so that the smallest N values from it could be choosen and also
%// get the selected row indices based on the sorting as row1
[f1,row1] = sort(f1)
%// Choose n and m based on the sorted indices and also chop off at N.
%// Use these n and m values to finally get f
n = n1(row1(1:N))
m = m1(row1(1:N))
f = f1(1:N)
Output
With N = 5, you would get -
n =
0
1
2
0
1
m =
0
0
0
1
1
f =
0
0.5000
1.0000
1.0000
1.1180
With N = 9, you would get -
n =
0
1
2
0
1
2
3
3
4
m =
0
0
0
1
1
1
0
1
0
f =
0
0.5000
1.0000
1.0000
1.1180
1.4142
1.5000
1.8028
2.0000
meshgrid and arrayfun can be used to generate an array of outputs for ranges of inputs as such
Code
nValues = 0:2
mValues = 0:3
[ii,jj] = meshgrid(mValues,nValues)
output = arrayfun(#func,ii,jj)
The two value vectors can be modified to take the range(s) of values required
Output
output =
0 0.5000 1.0000 1.5000
1.0000 1.1180 1.4142 1.8028
2.0000 2.0616 2.2361 2.5000
To give a result like the matrix in the question the following can be used (thanks #Divakar)
[jj(:),ii(:),arrayfun(#func,jj(:),ii(:))]
ans =
0 0 0
1.0000 0 0.5000
2.0000 0 1.0000
0 1.0000 1.0000
1.0000 1.0000 1.1180
2.0000 1.0000 1.4142
0 2.0000 2.0000
1.0000 2.0000 2.0616
2.0000 2.0000 2.2361
0 3.0000 3.0000
1.0000 3.0000 3.0414
2.0000 3.0000 3.1623
Something (probably rather inefficient) like this?
N = 100 % stop
i = 0
n = 0
m = 0
nout = [n]
mout = [m]
fout = [f(n,m)]
while i ~= N
a = f(n+1,m)
b = f(n,m+1)
if (a > b)
m = m + 1
nout = [nout n]
mout = [mout m]
fout = [fout b]
else
n = n + 1
nout = [nout n]
mout = [mout m]
fout = [fout a]
end if
i = i + 1
end while

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