So i have this data:
A=
2
4
8
9
4
6
1
3
And 3 interval
B=
1 4
5 8
9 12
How to make an output like this
Output=
1
1
2
3
1
2
1
1
The output is based on the interval
you can solve it in several ways. for example, with arrayfun:
A = [2 4 8 9 4 6 1 3].';
B = [1 4;
5 8;
9 12];
res = arrayfun(#(x) find((x >= B(:,1)) & (x <= B(:,2))),A);
If the interval always has the same length, as in your case 4, you can solve it as follows:
Output=ceil(A/4);
If it is not the case, and if not all numbers necessarily fall between any of the intervals, you can compute it as follows. A zero is outputted if a number does not fall within any of the intervals.
% example entry
A=[2 3 4 8 9 4 6 1 3]';
B=[1 4;5 7;9 12]';
Arep=A(:,ones(size(B,2),1)); % replicate array (alternatively use repmat)
Alog=Arep>=B(1,:)&Arep<=B(2,:); % conditional statements, make logical array
Output=Alog*(1:size(B,2))'; % matrix product with natural array to obtain indices
Related
I want to take the union of some of the rows of a matrix x. The row numbers of the rows whose union has to be taken are given by vector r. Is there any built-in function in MATLAB that can do it?
x = [1 2 4 0 0;
3 6 5 0 0;
7 8 10 12 9;
2 4 6 7 0;
3 4 5 8 12];
r = [1, 3, 5];
I think this will work for you - first, take the submatrix x(r,:) with the rows you want, and then find all the unique values in it:
unique(x(r,:))
ans =
0
1
2
3
4
5
7
8
9
10
12
You could do it like this
>>> union(union(x(r(1),:),x(r(2),:)),x(r(3),:))
ans =
0 1 2 3 4 5 7 8 9 10 12
or set up a for loop that iterates over the vector r to compute all the unions
I have a vector of 13 entities in Matlab.
a=[3 4 6 8 1 5 8 9 3 7 3 6 2]
I want to append values [1 2 3 4 5] at regular intervals at position 1 5 9 13 & 17.
The final value of a looks like this.
a=[1 3 4 6 2 8 1 5 3 8 9 3 4 7 3 6 5 2].
The values with italics show the appended values.
How can I do it?
Since you are looking for regular intervals, you can take advantage of the reshape and cat function:
a = [3 4 6 8 1 5 8 9 3 7 3 6 2];
v = [1 2 3 4 5];
l = [1 5 9 13 17];
interval = l(2)-l(1)-1; %computes the interval between inserts
amax = ceil(size(a,2)/interval) * interval; %calculating maximum size for zero padding
a(amax) = 0; %zero padding to allow `reshape`
b = reshape (a,[interval,size(v,2)]); %reshape into matrix
result = reshape(vertcat (v,b), [1,(size(b,1)+1)*size(b,2)]); %insert the values into the right position and convert back into vector
%remove padded zeros
final = result(result ~= 0) %remove the zero padding.
>>final =
Columns 1 through 16
1 3 4 6 2 8 1 5 3 8 9 3 4 7 3 6
Columns 17 through 18
5 2
Here's an approach using boolean-indexing -
% Inputs
a = [3 4 6 8 1 5 8 9 3 7 3 6 2]
append_vals = [1 2 3 4 5]
append_interval = 4 % Starting at 1st index
% Find out indices of regular intervals where new elements are to be inserted.
% This should create that array [1,5,9,13,17]
N_total = numel(a) + numel(append_vals)
append_idx = find(rem(0:N_total-1,append_interval)==0)
% Get boolean array with 1s at inserting indices, 0s elsewhere
append_mask = ismember(1:N_total,append_idx)
% Setup output array and insert new and old elements
out = zeros(1,N_total)
out(~append_mask) = a
out(append_mask) = append_vals
Alternatively, we can also use linear-indexing and avoid creating append_mask, like so -
% Setup output array and insert new and old elements
out = zeros(1,N_total)
out(append_idx) = append_vals
out(setdiff(1:numel(out),append_idx)) = a
a=[3 4 6 8 1 5 8 9 3 7 3 6 2]; % // Your original values
pos = [1 5 9 13 17]; % // The position of the values you want to insert
b=[1 2 3 4 5]; % // The values you want to insert
% // Pre-allocate a vector with the total size to hold the resulting values
r = zeros(size(a,2)+size(pos,2),1);
r(pos) = b % // Insert the appended values into the resulting vector first
r3 = r.' <1 % // Find the indices of the original values. These will be zero in the variable r but 1 in r3
ans =
0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1
ind= find(r3==1) % // Find the indices of the original values
ind =
2 3 4 6 7 8 10 11 12 14 15 16 18
r(ind) = a; % // Insert those into the resulting vector.
r.'
ans =
1 3 4 6 2 8 1 5 3 8 9 3 4 7 3 6 5 2
You can use this function to append a bunch of values to an existing vector, given their positions in the new vector:
function r=append_interval(a,v,p)
% a - vector with initial values
% v - vector containing values to be inserted
% p - positions for values in v
lv=numel(v); % number of elements in v vector
la=numel(a); % number of elements in a vector
column_a=iscolumn(a); % check if a is a column- or row- wise vector
tot_elements=la+lv;
% size of r is tha max between the total number of elements in the two vectors and the higher positin in vector p (in this case missing positions in a are filled with zeros)
lr=max([max(p) tot_elements]);
% initialize r as nan vector
r=zeros(column_a*(lr-1)+1,~column_a*(lr-1)+1)/0;
% set elements in p position to the corresponding values in v
r(p)=v;
% copy values in a in the remaining positions and fill with zeros missing entries (if any)
tot_missing_values=lr-tot_elements;
if(tot_missing_values)
remaining_values=cat(2-iscolumn(a),a,zeros(column_a*(tot_missing_values-1)+1,~column_a*(tot_missing_values-1)+1));
else
remaining_values=a;
end
% insert values
r(isnan(r))=remaining_values;
You can use row-wise or column-wise vectors; the orientation of r will be the same of that of a.
Input:
a =
3 4 6 8 1 5 8 9 3 7 3 6 2
v =
1 2 3 4 5
p =
1 5 9 13 17
Output:
>> append_interval(a,v,p)
ans =
1 3 4 6 2 8 1 5 3 8 9 3 4 7 3 6 5 2
Every sequence of positive positions is allowed and the function will pad for you with zeros the final vector, in case you indicate a position exceding the sum of the original vector and added items.
For example, if:
v3 =
1 2 3 4 5 6 90
p3 =
1 5 9 13 17 30 33
you get:
append_interval(a,v3,p3)
ans =
Columns 1 through 19
1 3 4 6 2 8 1 5 3 8 9 3 4 7 3 6 5 2 0
Columns 20 through 33
0 0 0 0 0 0 0 0 0 0 6 0 0 90
Hope this will help.
I apologize if this is a repeated question.
Suppose I have a matrix A
0 1 2 3 4 5 6 7
8 9 1 2 3 4 5 6
and a vector b [1,2,3,4,1,2,3,4]. Thus, matrix A contains multiple ordered measurements based on vector b.
How can I reshape the matrix to have dimension [2 2 4], such that A(:,:,1) = [0,4;8,3]?
I understand I need to reshape. I tried using permute, however it does not handle repeated indices.
Thanks!
You are close, you just need to sort the columns before reshaping them
A=[0 1 2 3 4 5 6 7; 8 9 1 2 3 4 5 6]
%A =
% 0 1 2 3 4 5 6 7
% 8 9 1 2 3 4 5 6
b=[1,2,3,4,1,2,3,4]
%b =
% 1 2 3 4 1 2 3 4
[~,idx]=sort(b)
%idx =
% 1 5 2 6 3 7 4 8
A=A(:,idx)
%A =
% 0 4 1 5 2 6 3 7
% 8 3 9 4 1 5 2 6
A=reshape(A,[2,2,4])
%A(:,:,1) =
% 0 4
% 8 3
%A(:,:,2) =
% 1 5
% 9 4
%A(:,:,3) =
% 2 6
% 1 5
%A(:,:,4) =
% 3 7
% 2 6
Be careful, this will only work if you can assure that each number in b is repeated same number of times.
Assuming your b is always some repeated 1:n pattern like it is in your question, you can use:
p=4 % number of indices
permute(reshape(A,size(A,1),p,[]),[1,3,2])
I would like to align and count vectors with different time stamps to count the corresponding bins.
Let's assume I have 3 matrix from [N,edges] = histcounts in the following structure. The first row represents the edges, so the bins. The second row represents the values. I would like to sum all values with the same bin.
A = [0 1 2 3 4 5;
5 5 6 7 8 5]
B = [1 2 3 4 5 6;
2 5 7 8 5 4]
C = [2 3 4 5 6 7 8;
1 2 6 7 4 3 2]
Now I want to sum all the same bins. My final result should be:
result = [0 1 2 3 4 5 6 7 8;
5 7 12 16 ...]
I could loop over all numbers, but I would like to have it fast.
You can use accumarray:
H = [A B C].'; %//' Concatenate the histograms and make them column vectors
V = [unique(H(:,1)) accumarray(H(:,1)+1, H(:,2))].'; %//' Find unique values and accumulate
V =
0 1 2 3 4 5 6 7 8
5 7 12 16 22 17 8 3 2
Note: The H(:,1)+1 is to force the bin values to be positive, otherwise MATLAB will complain. We still use the actual bins in the output V. To avoid this, as #Daniel says in the comments, use the third output of unique (See: https://stackoverflow.com/a/27783568/2732801):
H = [A B C].'; %//' stupid syntax highlighting :/
[U, ~, IU] = unique(H(:,1));
V = [U accumarray(IU, H(:,2))].';
If you're only doing it with 3 variables as you've shown then there likely aren't going to be any performance hits with looping it.
But if you are really averse to the looping idea, then you can do it using arrayfun.
rng = 0:8;
output = arrayfun(#(x)sum([A(2,A(1,:) == x), B(2,B(1,:) == x), C(2,C(1,:) == x)]), rng);
output = cat(1, rng, output);
output =
0 1 2 3 4 5 6 7 8
5 7 12 16 22 17 8 3 2
This can be beneficial for particularly large A, B, and C variables as there is no copying of data.
I'm very new to scilab syntax and can't seem to find a way to extract the even and odd elements of a matrix into two separate matrix, suppose there's a matrix a:
a=[1,2,3,4,5,6,7,8,9]
How do I make two other matrix b and c which will be like
b=[2 4 6 8] and c=[1 3 5 7 9]
You can separate the matrix by calling row and column indices:
a=[1,2,3,4,5,6,7,8,9];
b=a(2:2:end);
c=a(1:2:end);
[2:2:end] means [2,4,6,...length(a)] and [1:2:end]=[1,3,5,...length(a)]. So you can use this tip for every matrix for example if you have a matrix a=[5,4,3,2,1] and you want to obtain the first three elements:
a=[5,4,3,2,1];
b=a(1:1:3)
b=
1 2 3
% OR YOU CAN USE
b=a(1:3)
If you need elements 3 to 5:
a=[5,4,3,2,1];
b=a(3:5)
b=
3 2 1
if you want to elements 5 to 1, i.e. in reverse:
a=[5,4,3,2,1];
b=a(5:-1:1);
b=
1 2 3 4 5
a=[1,2,3,4,5,6,7,8,9];
b = a(mod(a,2)==0);
c = a(mod(a,2)==1);
b =
2 4 6 8
c =
1 3 5 7 9
Use mod to check whether the number is divisible by 2 or not (i.e. is it even) and use that as a logical index into a.
The title is about selecting rows of a matrix, while the body of the question is about elements of a vector ...
With Scilab, for rows just do
a = [1,2,3 ; 4,5,6 ; 7,8,9];
odd = a(1:2:$, :);
even = a(2:2:$, :);
Example:
--> a = [
5 4 6
3 6 5
3 5 4
7 0 7
8 7 2 ];
--> a(1:2:$, :)
ans =
5 4 6
3 5 4
8 7 2
--> a(2:2:$, :)
ans =
3 6 5
7 0 7