What does Array(True/False Array) does in MATLAB? [duplicate] - arrays

This question already has an answer here:
Linear indexing, logical indexing, and all that
(1 answer)
Closed 1 year ago.
I am trying to understand what happens in MATLAB for this certain line of code
good_mintratio=handles.mintratio(handles.good)
handles.good is an array with size (48x60) where all the elements are 1. handles.mintratio is also an array with size (48x60) where it contains floats.
I ran the following simple code to understand what it exactly does but I am not quite sure what is really happening.
For this piece of code,
A = [1,2,3; 4,5,6];
B = [1,1,1; 1,1,1];
C=A(B);
This returns C = [1,1,1;1,1,1]
It seems like C is like B but contains the elements of A where the elements of B is the indexes for A.
A = [1,2,3; 4,5,6];
B = [2,1,1; 1,5,1];
C=A(B);
Like, this will make C = [4,1,1;1,3,1]
But
good_mintratio=handles.mintratio(handles.good)
this forms a colmun with size (2880,1). It seems like all the elements got combined in to a single colmun but not sure why the size changed. Also, if handles.good has some 0's (which means false in MATLAB, right?), would that change the result?

When you use indexing by arrays (As in C = A(B);) there are 2 options:
The array B is based on non logical numbers (Double usually): The output is based on the linear indexing of the array A.
The array B is based on logical elements: The output is a vector of the elements where true was in B.
For example:
clear();
mA = reshape(1:9, 3, 3);
mB = randi([1, 9], 3, 3);
mC = logical(randi([0, 1], 3, 3));
mA(mB)
mA(mC)
Then the output:
ans =
5 9 5
9 8 9
8 7 4
ans =
2
5
8

Related

Stack copies of elements of a vector [duplicate]

This question already has answers here:
MATLAB: Duplicate each element of a vector? [closed]
(1 answer)
Element-wise Matrix Replication in MATLAB
(1 answer)
Element-wise array replication in Matlab
(7 answers)
Closed 5 years ago.
I have a vector that has N=1263 entries:
temp=[14, 0.5, ..., 12]
I want to make a vector which repeats entry 1, i.e. 14, 42 times, then entry 2, i.e. 0.5, 42 times and similarly all through the vector. It should produce a vector with size 53046x1.
The following code does the work for a simple case:
F = [1 4 9];
R = [repmat(F(1),[3,1]); repmat(F(2),[3,1]); repmat(F(3),[3,1])]
R = [1 1 1 4 4 4 9 9 9]
but it is cumbersome when N becomes large. Is there a faster way around this?
This is exactly what repelem (introduced in R2015a) is for. For your actual problem, you would use:
R = repelem(temp.',42); %This will repeat each entry of 'temp' 42 times
For the given example,
F = [1 4 9];
R = repelem(F.',3); %This will repeat each entry of 'F' 3 times
You can also do it with this:
R = ones(42,1)*temp;
R = R(:);
Kind of an unusual way of doing this but it works
https://www.mathworks.com/help/matlab/ref/kron.html
All you need to do is include your matrix as well as a ones matrix of the length of the repetition.
R = kron(F(:),ones(42,1));
R = reshape(repmat(F, 42, 1), [], 1);

matlab making repetitions of data from one array into another array [duplicate]

This question already has answers here:
Element-wise array replication in Matlab
(7 answers)
Closed 6 years ago.
I would appreaciate a lot if you help. I am beginner in programming. I am using Matlab. So, I have an array which is 431x1 type - double; there i have numbers 1 to 6; for ex: 1 4 5 3 2 6 6 3 3 5 4 1 ...; what I want to do is I need to make a new array where I would have each element repeat for 11 times; for ex: a(1:11)=1; a(12:22)=4; a(23:33)=5; or to illustrate differently : a=[1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4...];
I tried doing it in a loop but had some problems, which way could you suggest, do you know any function I could take advantage of?
First of all, it would help if you could format your code is separate blocks to make your question easier to read...
Let's say you had an array of length Nx1 as:
x = [1 2 3 4 5 ...]';
You could construct a loop and concatenate as:
for i = 1 : length(x)
for i = 1: length(x)
y(1 + (i - 1) * 11 : 1 + i * 11) = x(i); % Copy to a moving block
end
y(end) = []; % Delete the superfluous one at the end
You could also look at functions like repmat in the MATLAB help for replicating arrays.
Try this (NRepis how many times you want it repeated):
x = [1, 2, 3, 4, 5];
NRep = 5;
y = reshape(repmat(x,[NRep,1]),[1,length(x)*NRep])
Since it's a little cumbersome to write that out, I also particularly enjoy to use this "hack":
x = [1, 2, 3, 4, 5];
NRep = 5;
y = kron(x, ones(1,NRep));
Hope that helps!
P.S.: This is designed for row vectors only. Though if you need column vectors it's easy to modify.
edit: Of course, if you're post-R2015a you can just use y=repelem(x,NRep). I tend to forget about those because I work on older Matlabs (and sometimes it's not such a bad idea to be a bit backward compatible). Thanks to #rahnema1 for reminding me.

How to randomly fill a 1x5 array with the numbers from 1 to 5 without repeating a number? [duplicate]

This question already has answers here:
shuffle matrix element in matlab
(2 answers)
Closed 6 years ago.
I'm looking to fill a 1x5 array with the numbers from 1 to 5, but I don't want to repeat a number.
I've tried this, which allows numbers to repeat:
r = randi([1,5],5,1)
What I'm looking for is something that will generate ex. [5 2 3 1 4] randomly. Is there a function in Matlab that will allow me to do so?
Try randperm. It does exactly what you want.
r = randperm(5)
From the documentation:
p = randperm(n) returns a row vector containing a random permutation
of the integers from 1 to n inclusive
You can also check out randsample if you have the statistic toolbox.

How to get elements larger than x in a given range?

Given a matrix A, how do I get the elements (and their indices) larger than x in a specific range?
e.g.
A = [1:5; 2:6; 3:7; 4:8; 5:9]
A =
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
And for instance I want all elements larger than 5 and appear in the range A(2:4,3:5). I should get:
elements:
6 , 6 , 7 , 6 , 7 , 8
indices:
14, 18, 19, 22, 23, 24
A(A>5) would give me all entries which are larger than 5.
A(2:4,3:5) would give all elements in the range 2:4,3:5.
I want some combination of the two. Is it possible or the only way is to put the needed range in another array B and only then perform B(B>5)? Obviously 2 problems here: I'd lose the original indices, and it will be slower. I'm doing this on a large number of matrices.
Code. I'm trying to avoid matrix multiplication, so this may look a bit odd:
A = [1:5; 2:6; 3:7; 4:8; 5:9];
[r,c] = meshgrid(2:4,3:5);
n = sub2ind(size(A), r(:), c(:));
indices = sort(n(A(n) > 5)); %'skip sorting if not needed'
values = A(indices);
Explanation. The code converts the Cartesian product of the subscripts to linear indices in the A matrix. Then it selects the indices that respect the condition, then it selects the values.
However, it is slow.
Optimization. Following LuisMendo's suggestion, the code may be sped up by replacing the sub2ind-based linear index calculation with a handcrafted linear index calculation:
A = [1:5; 2:6; 3:7; 4:8; 5:9];
%'For column-first, 1-based-index array memory '
%'layout, as in MATLAB/FORTRAN, the linear index '
%'formula is: '
%'L = R + (C-1)*NR '
n = bsxfun(#plus, (2:4), (transpose(3:5) - 1)*size(A,1));
indices = n(A(n) > 5);
values = A(indices);
If you only need the values (not the indices), it can be done using the third output of find and matrix multiplication. I don't know if it will be faster than using a temporary array, though:
[~, ~, values] = find((A(2:4,3:5)>5).*A(2:4,3:5));
Assuming you need the linear indices and the values, then if the threshold is positive you could define a mask. This may be a good idea if the mask can be defined once and reused for all matrices (that is, if the desired range is the same for all matrices):
mask = false(size(A));
mask(2:4,3:5) = true;
indices = find(A.*mask>5);
values = A(indices);
its a little clunky, but:
R = 2:4;
C = 3:5;
I = reshape(find(A),size(A))
indicies = nonzeros(I(R,C).*(A(R,C)>5))
values = A(indicies)

How would I go about this task- Matlab [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to store value generated from nested for loop in an array, in Matlab?
I have an array of digits. e.g. x = [4,9,8]. I use find(x) to obtain [1,2,3], then find(x)+length(x) to obtain [4,5,6].
I want this(in this case, adding 3 to the array, to make a sequence of 1,2,3 4,5,6 7,8,9...) to go on n number of times, so I require a loop.
Now with the array x, I want to add [4,9,8] to [1,2,3] , which gives [5,11,11].
I have [1,2,3]...[10,11,12]...[n,n+1,n+2] from find(x)+length(x) looped, I want to add elements in x to the elements in corresponding positions, in the array that is going up in three.
So, for example, [4,5,6] 5 is in position 2. x=[4,9,8]. 9 is in position 2 within x. Therefore, I want to add 9 to 5. I want to do this for each element (in this case, each of the three elements). I would add 9 to 11, and 9 to 11 as both numbers are in position '2' in their respective arrays.
I was thinking of using a nested for loop, to take care of the find(x)+length(x). I am just unsure of how to make the 'location additions' happen.
I would then like to store the results of the additions in a separate array.
Thanks in advance for your time and help!
So, we start with
x = [4,9,8]
Let's add [1, 2, 3]
x + [1, 2, 3]
ans =
5 11 11
A more flexible way
x + (1 : length(x))
ans =
5 11 11
If you do not want to start at 1 but at b (say, we add [5, 6, 7] to x):
b = 5;
x + b + (0 : length(x) - 1)
ans =
9 15 15
I think this should get you going and you can add your loop now.
Warning: You have a very strange way of using find(). Just to make sure: find(x) returns the indices of the non-zero entries in x. If all elements of the vector x are non-zero, you have the equality
find(x) == 1 : length(x)
If any element in x is zero, you run into problems, when adding it to find(x):
x = [4, 9, 0, 8];
find(x)
ans =
1 2 4
x + find(x)
Error using +
Matrix dimensions must agree.

Resources