matrix assignment from a matrix A to a matrix B using conditional statements based on a third matrix C - matlab

I have two questions if you can kindly respond:
Q1) I have a matrix choice, where each person is making 4 of any possible choices, denoted as 1, 2, 3 and 4.
I have three matrixes A1, A2, A3 with income information for each person and each time period. Say I have n people and t time periods so A1, A2, A3 are n-by-t and choice is n-by-t.
Now I want to make another matrix B, where B will pick the element from A according to the value in the choice matrix, i.e. if choice(n,t)==1, then B(n,t) = A1(n,t). If choice(n,t)==2, then B(n,t) = A2(n,t), and so on.
I have tried the for loop and the if statement, I am unable to do it. Please help.
Q2) I have a matrix A of incomes. A is dimension n-by-t. Some people have low income, some have high income. Say anyone with income<1000 is low and above 1000 is high. At the end of my simulations, I need to know whether each person was high income or low income. How can I make a high income and low income matrix from the bigger matrix?

Q1:
C = choice %else the code gets too long
B = A1 .* (C==1) + A2 .* (C==2) + A3 .* (C==3)
I'm not sure how you want to handle the value '4' in B if you only have A1 A2 A3, but this should work.
[EDIT]:
If the choice is '4', that element of B will be 0 for the B i defined above.
Q2:
this one's a little vague. Maybe this is what you wanted:
HighIncome = A > 1000
LowIncome = A <= 1000
If this doesn't do it, please explain your objective more precisely.
[EDIT]:
Based on your slightly less vague explanation on Q2 it sounds like you wan't something like this:
A_high_income = A .* (A > 1000)
A_low_income = A .* (A <= 1000)
CHOICE_high_income = choice .* (A > 1000)
CHOICE_high_income = choice .* (A <= 1000)
The high income matrices have zeros at the low-income positions and vice versa.
This doesn't make very much sens IMHO, but it's the closest I could get to your description.
If this doesn't do it, follow the instructions in my comment below and post some examples.

Q1: You can use three simple statements and some logical indexing.
B = A1;
B(choice == 2) = A2(choice == 2);
B(choice == 3) = A3(choice == 3);
Q2: To separate A and choice into two parts based on income, you first find the indices of "low income" rows and use that to get rows from the matrices.
lowIncomeNdx = any(A < 1000, 2);
lowIncome = A(lowIncomeNdx, :);
lowIncomeChoice = choice(lowIncomeNdx, :);
highIncome = A(~lowIncomeNdx, :);
highIncomeChoice = choice(~lowIncomeNdx, :);

Related

MATLAB Simple Calculation

I am working on MATLAB on my own, and was doing problem 9 on Project Euler
It states
" A Pythagorean triplet is a set of three natural numbers, a < b < c, for which,
a2 + b2 = c2
For example, 32 + 42 = 9 + 16 = 25 = 52.
There exists exactly one Pythagorean triplet for which a + b + c = 1000.
Find the product abc."
Below is the code I wrote; however, it compiles, but does not produce and output. I was hoping to get some feedback on what's wrong, so I can fix it.
Thanks,
syms a;
syms b;
syms c;
d= 1000;
d= a + b + c ;
ab= a.^2 + b.^2;
ab= c.^2;
c
I propose a vectorized way (that is, without using loops) to solve the problem. It may seem relatively complicated, especially if you come from other programming languages; but for Matlab you should get used to this way of approaching problems.
Ingredients:
Vectorization;
Indexing;
Transpose;
Implicit singleton expansion;
hypot;
find.
Read up on these concepts if you are not familiar with them, and then try to solve the problem yourself (which of course is the whole point of Project Euler). As a hint, the code below proceeds along these lines:
Generate a 1×1000 vector containing all possible values for a and b.
Compute a 1000×1000 matrix with the values of c corresponding to each pair a, b
From that compute a new matrix such that each entry contains a+b+c
Find the row and column indices where that matrix equals 1000. Those indices are the desired a and b (why?).
You'll get more than one solution (why?). Pick one.
Compute the product of the obtained a and b and the corresponding c.
Once you have tried yourself, you may want to check the code (move the mouse over it):
ab = 1:1000; % step 1
cc = hypot(ab,ab.'); % step 2
sum_abc = ab+ab.'+cc; % step 3
[a, b] = find(sum_abc==1000); % step 4
a = a(1); b = b(1); % step 5
prod_abc = a*b*cc(a,b); % step 6

Iterating in a matrix avoiding loop in MATLAB

I am posing an interesting and useful question that needs to be carried out in MATLAB. It is about efficiency of programming by avoiding using Loops"
Assume a matrix URm whose columns are products and rows are people. The matrix entries are rating of people to these products, and this matrix is sparse as each person normally rates only few products.
URm [n_u, n_i]
Another matrix of interest is F, which contains attribute for each of the products and the attribute is of fixed length:
F [n_f,n_i]
We divide the URm into two sub-matrices randomly: URmTrain and URmTest where the former is used for training the system and the latter for test. These two matrices have similar rows (users) but they could have different number of columns (products).
We can find the similarity between items very fast using pdist() or Matrix transpose:
S = F * F' ;
For each row (user) in URmTest:
URmTestp = zeros(size(URmTest));
u = 1 ; %% Example user 1
for i = 1 : size(URmTest,2)
indTrain = find(URmTrain(u,:)) ; % For each user, search for items in URmTrain that have been rated by the the user (i.e. the have a rating greater than zero)
for j = 1 : length(indTrain)
URmTestp(u,i) = URmTestp(u,i) + S(i,indTrain(j))*URmTrain(u,indTrain(j))
end
end
where URmp is the predicted version of URm and we can compute an error on how good our prediction has been.
Example
Lets's make a simple example. Let's assume the items user 1 has rated items 3 , 5 and 17:
indTrain = [3 5 17]
For each item j in URmTest, I want to predict the rating using the following formula:
URmTestp(u,j) = S(j,3)*URmTrain(u,3) + S(j,5)*URmTrain(u,5) + S(j,17)*URmTrain(u,17)
Once completed this process needs to be repeated for all users.
As URm is typically very big, I prefer options which use least amount of 'loops'. We may be able to take advantage of bsxfun but I am not sure if we can.
Please suggest me ides that can help on accelerating this process as rapid as possible. Thank you
I'm still not sure I completely understand your problem. But it seems to me that if you pre-compute s_ij as
s_ij = F.' * F %'// [ni x ni] matrix
then what you're after is simply
URmTestp(u,indTest) = URmTrain(u,indTrain) * s_ij(indTrain,indTest);
% or
%URmTestp(u,:) = URmTrain(u,indTrain) * s_ij(indTrain,:);
or if you only compute a smaller s_ij block only for the necessary arrays,
s_ij = F(:,indTrain).' * F(:,indTest);
then
URmTestp(u,indTest) = URmTrain(u,indTrain) * s_ij;
Alternatively, you can always compute the necessary subblock of s_ij on the fly:
URmTestp(u,indTest) = URmTrainp(u,indTrain) * F(:,indTrain).'*F(:,indTest);
If I understand correctly that indTest and indTrain are functions of u, such as
URmTestp = zeros(n_u,n_i); %// pre-allocate here!
for u=1:n_u
indTest = testCell{u};
indTrain = trainCell{u};
URmTestp(u,indTest) = URmTrainp(u,indTrain) * F(:,indTrain).'*F(:,indTest); %'
...
end
then probably not much can be vectorized on this loop, unless there's a very tricky indexing scheme that allows you to use linear indices. I'd stick with this setup.

How to get the union of the two 3D matrix?

I have two 3D matrix A and B. The size of A and B are both 40*40*20 double.
The values in matrix A and B are either 0 or 1. The number of "1" in A are 100,
the number of "1" in B are 50. The "1" in matrix A and B may or may not be in
the same coordinates. I want to get the union of matrix A and B, called C. The values in 3D matrix C is either "1" or "0". The number of "1" in C is less than or equal to 150. My question is how to get the 3D matrix C in Matlab?
You can use the operator or, which is a logical or. So or(a,b) is equivalent to the logical operation a | b.
C = or(A,B);
C = a | b;
| and or are the same operator in MatLab, it's just two different way to call it.
I think this is the best solution as long as it's integrated into MatLab. However, you have plenty different ways to do it.
Just as an example, you can do
C = logical(a+b);
logical is an operator that convert every value into logical values. Long story short, it will replace any value different of 0 by 1.
You can approach it in 2 ways. The more efficient one is using vectors but you can also do it in classical nested for loops.
A = rand(40,40,20);
A = A > 0.01; # Get approximate 320 ones and rest zeros
B = rand(40,40,20);
B = B > 0.005; # Get approximate 160 ones and rest zeros
C = zeros(size(A));
for iter1 = 1:size(A,1)
for iter2 = 1:size(A,2)
for iter3 = 1:size(A,3)
C(iter1,iter2,iter3) = A(iter1,iter2,iter3)|B(iter1,iter2,iter3)
end
end
end
This method will be very slow. You can vectorized it to improve performance
C = A|B

calculate maximum distance with large vectors

ok so I have 2 vectors (A and B) with different lengths (in this example lets say 100000 and 300000) and I wish to obtain the indexes that have the largest difference.
Something like this
distAB=bsxfun(#(v1,v2) abs(v1-v2),A,B));
[~,lin_indx]=max(distAB(:));
[x_indx,y_indx]=ind2sub(size(A),lin_indx)
The problem here is that my vectors A and B are too large and producing the matrix "distAB" is too expensive. I would wish to obtain the min directly with the bsxfun.
If you want to maximize distance, the search can be reduced to just two candidate pairs: max(A), min(B)) or min(A), max(B)).
So just try those two pairs:
[ma_val, ma_ind] = min(A);
[Ma_val, Ma_ind] = max(A);
[mb_val, mb_ind] = min(B);
[Mb_val, Mb_ind] = max(B);
diff1 = abs(Mb_val-ma_val);
diff2 = abs(Ma_val-mb_val);
if diff1 > diff2
result_ind_A = ma_ind;
result_ind_B = Mb_ind;
result_value = diff1;
else
result_ind_A = Ma_ind;
result_ind_B = mb_ind;
result_value = diff2;
end
If you want to minimize distance: sort the concatenation of A and B, keeping track of which element is from A and which from B:
C = sortrows([A(:) zeros(numel(A),1); B(:) ones(numel(B),1)] ,1);
%// C(k,2)==0 indicates element k comes from A; 1 indicates from B
Now, use a for loop to traverse all elements in C(:,1) that come from B. For each such element, find the two elements from A that are located closest above and to below left in C. Those are the only candidates from A to be nearest to that element from A.
So for each element from B you have two candidates from A, which reduces the complexity of the problem significantly.
You can calculate distAB this way with the built-in #minus which could be more efficient -
distAB = abs(bsxfun(#minus,A(:).',B(:)))
Luis' approach of sorting will probably be the fastest. But if you have the statistics toolbox installed, you could use the function knnsearch, which makes for a simple yet efficient solution.
(There are also some similar free versions of this on the File Exchange. Look for: kd tree nearest neighbor)
One extra benefit of this solution is that it also works for 2D, 3D, ..., nD data.
[Is, D] = knnsearch(A,B,'K',1);
[~,j] = min(D); i = Is(j);
[A(i), B(j)]

How to perform a column by column circular shift of a matrix without a loop

I need to circularly shift individual columns of a matrix.
This is easy if you want to shift all the columns by the same amount, however, in my case I need to shift them all by a different amount.
Currently I'm using a loop and if possible I'd like to remove the loop and use a faster, vector based, approach.
My current code
A = randi(2, 4, 2);
B = A;
for i = 1:size( A,2 );
d = randi( size( A,1 ));
B(:,i) = circshift( A(:,i), [d, 0] );
end
Is is possible to remove the loop from this code?
Update I tested all three methods and compared them to the loop described in this question. I timed how long it would take to execute a column by column circular shift on a 1000x1000 matrix 100 times. I repeated this test several times.
Results:
My loop took more than 12 seconds
Pursuit's suggestion less than a seconds
Zroth's orginal answer took just over 2 seconds
Ansari's suggest was slower than the original loop
Edit
Pursuit is right: Using a for-loop and appropriate indexing seems to be the way to go here. Here's one way of doing it:
[m, n] = size(A);
D = randi([0, m - 1], [1, n]);
B = zeros(m, n);
for i = (1 : n)
B(:, i) = [A((m - D(i) + 1 : m), i); A((1 : m - D(i) ), i)];
end
Original answer
I've looked for something similar before, but I never came across a good solution. A modification of one of the algorithms used here gives a slight performance boost in my tests:
[m, n] = size(A);
mtxLinearIndices ...
= bsxfun(#plus, ...
mod(bsxfun(#minus, (0 : m - 1)', D), m), ...
(1 : m : m * n));
C = A(idxs);
Ugly? Definitely. Like I said, it seems to be slightly faster (2--3 times faster for me); but both algorithms are clocking in at under a second for m = 3000 and n = 1000 (on a rather old computer, too).
It might be worth noting that, for me, both algorithms seem to outperform the algorithm provided by Ansari, though his answer is certainly more straightforward. (Ansari's algorithm's output does not agree with the other two algorithms for me; but that could just be a discrepancy in how the shifts are being applied.) In general, arrayfun seems pretty slow when I've tried to use it. Cell arrays also seem slow to me. But my testing might be biased somehow.
Not sure how much faster this would be, but you could try this:
[nr, nc] = size(A);
B = arrayfun(#(i) circshift(A(:, i), randi(nr)), 1:nc, 'UniformOutput', false);
B = cell2mat(B);
You'll have to benchmark it, but using arrayfun may speed it up a little bit.
I suspect, your circular shifting, operations on the random integer matrix donot make it any more random since the numbers are uniformly distributed.
So I hope your question is using randi() for demonstration purposes only.