Create random values in vector Matlab - matlab

I have this vector:
Population = [3, 5, 0, 2, 0, 5, 10, 50, 0, 1];
And i need to fill this vector with a random value between 1 and 4 only where have 0 value in vector.
How i can do it ?
Edit: there's a way to do it using randperm function?

First, find zero elements, then generate random values, then replace those elements:
Population = [3, 5, 0, 2, 0, 5, 10, 50, 0, 1];
idx = find(Population==0);
Population(idx) = 3 * rand(size(idx)) + 1;
If you need integers (didn't specify), just round the generated random numbers in the last statement, like this round(3*rand(size(idx))+1); or use randi (as suggested in answer by #OmG): randi([1,4], size(idx)).

You can use the following code:
ind = find(~Population); % find zero places
Population(ind) = randi(4,1,length(ind)); % replace them with a random integer

Related

Find the largest index of the minimum in Matlab

I have an array of positive numbers and there are some duplicates. I want to find the largest index of the minimum value.
For example, if a=[2, 3, 1, 1, 4, 1, 3, 2, 1, 5, 5] then [i, v] = min(a) returns i=3, however I want i=9.
Using find and min.
A = [2, 3, 1, 1, 4, 1, 3, 2, 1, 5, 5];
minA = min(A);
maxIndex = max(find(A==minA));
min get the minimun value, and find return de index of values that meet the condition A==minA. max return de maximun index.
Here's a different idea, which only requires one function, sort:
[~,y] = sort(a,'descend');
i = y(end)
ans =
9
You can use imreginalmin as well with time complexity O(n):
largestMinIndex = find(imregionalmin(A),1,'last');

How do I do "map" in octave/matlab? [duplicate]

This question already has answers here:
Map function in MATLAB?
(7 answers)
Closed 8 years ago.
Here's a bit of octave code
>> [4,5]([1,2,1])
ans =
4 5 4
I'd call that mapping the function 1->4, 2->5 over the vector [1,2,1].
But the map I want to do is 0->1,25->2,240->9, NaN->0 over a very long vector.
I'd also like it to bomb if there are any values except 0,25,240,NaN in the vector.
I can see various ways to make this happen, none of them elegant, and wondered if there was an idiomatic way to express it.
If you can use MATLAB, I would recommend you use the containers.Map paradigm, which is essentially an associative array that performs key/value lookups. It also spits out errors if you throw in a value that is not part of the dictionary. As such, you simply provide an input/output relationship for each element in your mapping. The inputs are what are known as keys, and the outputs are what are known as values.
Once you're finished, you provide a cell array of input values into your dictionary / associate array with the values function, then convert this cell array back into a numeric vector when you're finished. Judging from your input/output pairs, you want the inputs to be double and the outputs to be double as well. However, the problem with containers.Map is that NaN can't be used as a key. As such, a workaround would be to convert each element in your input numeric vector as a cell array of character keys, with the outputs defined as a cell array of character values.
We can achieve this with arrayfun, which performs an operation over each value in an array. This is very much like a for loop, but what's special is that if you specify the uni flag to be 0, the output of each corresponding element will be converted into a string. You then create your dictionary with these cell array of characters. Now, to do the mapping on your inputs, you'll have to convert these into a cell array of characters as well, then use values to get what the corresponding outputs are, then use str2double to convert each output cell element back and place it into a numeric array.
As such, borrowing from huntj's sample input, this is what you would have to do:
%// Input-Output relationships
in = [0,25,240,NaN];
out = [1,2,9,0];
%// Test inputs
vector = [0, 25, 240, NaN, 0, 25, 240, NaN];
% // For declaring our dictionary
in_cell = arrayfun(#num2str, in, 'uni', 0);
out_cell = arrayfun(#num2str, out, 'uni', 0);
% // Input test into dictionary
vector_cell = arrayfun(#num2str, vector, 'uni', 0);
% // Create dictionary
dict = containers.Map(in_cell, out_cell);
% // Put in inputs to be mapped
output_cell = values(dict,vector_cell);
% // Convert back to numeric array
output = str2double(output_cell);
This is what I get with the above code, with our final output stored in output:
output =
1 2 9 0 1 2 9 0
The following code is probably not elegant, but it is vectorized, at least.
vector = [0, 25, 240, NaN, 0, 25, 240, NaN];
old_value = [0, 25, 240, NaN];
new_value = [1, 2, 9, 0];
assert(size_equal(old_value, new_value))
total_mask = false;
for idx = 1:numel(old_value)
if isnan(old_value(idx))
partial_mask = isnan(vector);
else
partial_mask = vector == old_value(idx);
endif
vector(partial_mask) = new_value(idx);
total_mask |= partial_mask;
endfor
assert(all(total_mask), "some values were unexpected")
vector
which gives
1 2 9 0 1 2 9 0
and yields an error if a value is not in the old_values given.
EDIT [more compact, but more memory hungry and not faster]:
vector = [0, 25, 240, NaN, 0, 25, 240, NaN];
old_values = [0, 25, 240, NaN];
new_values = [1, 2, 9, 0];
mask__ = vector == old_values(:);
mask__(isnan(old_values), :) = isnan(vector);
assert(all(any(mask__, 1)), "some values were unexpected")
vector = cellfun(#(mask_) new_values(mask_), num2cell(mask__, 1))
This can be easily done through logical indexing. Using huntj's starting vectors:
allowed = [0, 25, 240];
v = [0; 25; 240; NaN; 0; 25; 240; NaN];
notAllowed = not(any(bsxfun(#eq,v,allowed),2));
notNaN = not(isnan(v));
if any(notAllowed & notNaN)
error('Illegal entry');
end
v( v == 0 ) = 1;
v( v == 25 ) = 2;
v( v == 240 ) = 9;
v( isnan(v) ) = 0;
In order for the bsxfun() to work, v needs to be a column vector. NaN was not included in the allowed table since NaN == NaN is always false.

Sequence in MATLAB

Write a single MATLAB expression to generate a vector that contains first 100 terms of the following sequence: 2, -4, 8, -16, 32, …
My attempt :
n = -1
for i = 1:100
n = n * 2
disp(n)
end
The problem is that all values of n is not displayed in a single (1 x 100) vector. Neither the alternating positive and negative terms are shown. How to do that ?
You are having a geometric series where r = -2.
To produce 2, -4, 8, -16, 32, type this:
>>-(-2).^[1:5]
2, -4, 8, -16, 32
You can change the value of 5 accordingly.
Though there are better methods, as mentioned in the answer by #lakesh. I will point out the mistakes in your code.
By typing n = n * 2, how can it become a vector?
By doing n=n * 2, you are going to generate -2, -4, -8, -16, ...
Therefore, the correct code should be:
n = -1
for i = 2:101 % 1 extra term since first term has to be discarded later
n(i) = -n(i-1) * 2;
disp(n)
end
You can discard first element of n, to get the exact series you want.
n(end)=[];

How to get a regular sampled matrix in Scilab

I'm trying to program a function (or even better it it already exists) in scilab that calculates a regular timed samples of values.
IE: I have a vector 'values' which contains the value of a signal at different times. This times are in the vector 'times'. So at time times(N), the signal has value values(N).
At the moment the times are not regular, so the variable 'times' and 'values' can look like:
times = [0, 2, 6, 8, 14]
values= [5, 9, 10, 1, 6]
This represents that the signal had value 5 from second 0 to second 2. Value 9 from second 2 to second 6, etc.
Therefore, if I want to calculate the signal average value I can not just calculate the average of vector 'values'. This is because for example the signal can be for a long time with the same value, but there will be only one value in the vector.
One option is to take the deltaT to calculate the media, but I will also need to perform other calculations:average, etc.
Other option is to create a function that given a deltaT, samples the time and values vectors to produce an equally spaced time vector and corresponding values. For example, with deltaT=2 and the previous vectors,
[sampledTime, sampledValues] = regularSample(times, values, 2)
sampledTime = [0, 2, 4, 6, 8, 10, 12, 14]
sampledValues = [5, 9, 9, 10, 1, 1, 1, 6]
This is easy if deltaT is small enough to fit exactly with all the times. If the deltaT is bigger, then the average of values or some approximation must be done...
Is there anything already done in Scilab?
How can this function be programmed?
Thanks a lot!
PS: I don't know if this is the correct forum to post scilab questions, so any pointer would also be useful.
If you like to implement it yourself, you can use a weighted sum.
times = [0, 2, 6, 8, 14]
values = [5, 9, 10, 1, 6]
weightedSum = 0
highestIndex = length(times)
for i=1:(highestIndex-1)
// Get the amount of time a certain value contributed
deltaTime = times(i+1) - times(i);
// Add the weighted amount to the total weighted sum
weightedSum = weightedSum + deltaTime * values(i);
end
totalTimeDelta = times($) - times(1);
average = weightedSum / totalTimeDelta
printf( "Result is %f", average )
Or If you want to use functionally the same, but less readable code
timeDeltas = diff(times)
sum(timeDeltas.*values(1:$-1))/sum(timeDeltas)

Aggregate 3rd dimension of a 3d array for the subscripts of the first dimension

I have a 3 Dimensional array Val 4xmx2 dimension. (m can be variable)
Val{1} = [1, 280; 2, 281; 3, 282; 4, 283; 5, 285];
Val{2} = [2, 179; 3, 180; 4, 181; 5, 182];
Val{3} = [2, 315; 4, 322; 5, 325];
Val{4} = [1, 95; 3, 97; 4, 99; 5, 101];
I have a subscript vector:
subs = {1,3,4};
What i want to get as output is the average of column 2 in the above 2D Arrays (only 1,3 an 4) such that the 1st columns value is >=2 and <=4.
The output will be:
{282, 318.5, 98}
This can probably be done by using a few loops, but just wondering if there is a more efficient way?
Here's a one-liner:
output = cellfun(#(x)mean(x(:,1)>=2 & x(:,1)<=4,2),Val(cat(1,subs{:})),'UniformOutput',false);
If subs is a numerical array (not a cell array) instead, i.e. subs=[1,3,4], and if output doesn't have to be a cell array, but can be a numerical array instead, i.e. output = [282,318.5,98], then the above simplifies to
output = cellfun(#(x)mean(x(x(:,1)>=2 & x(:,1)<=4,2)),Val(subs));
cellfun applies a function to each element of a cell array, and the indexing makes sure only the good rows are being averaged.