How to insert elements in a vector at regular intervals in Matlab - matlab

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.

Related

find index of a specific number row wise

Consider the following example
A =
6 9 4 7 10
3 6 5 5 9
10 4 9 8 6
10 6 3 4 6
6 3 3 8 6
6 4 4 4 5
5 10 8 5 7
10 10 8 8 7
5 7 8 9 9
3 3 6 3 9
[~,Inx] =max(A, [],2)
Inx =
5
5
1
1
4
1
2
1
4
5
The above code returns index of the maximum number along each column like in first row the max number is 10 in 5th row so Inx(1) = 5
Can we do the same thing for find ? like for example if I want to find a specific number in each row lets say 8
>> find(A == 8)
ans =
27
28
29
33
35
38
I will get the indices but not row wise like we get for the max() is there some way to do minipulate find to get that ? or else some other way
Update : I know we can use [row,col,v] = find(___) but there is one problem with that it only returns for the rows where the value is present
You can simply convert A to a logical matrix where it's 1 if equal to 8 and 0 otherwise. Then you can use the second output of max to find the column which contains the first 8 in each row. If a row doesn't contain any 8's the first output of max will be a 0 and the second output will be 1.
You can multiply the first and second outputs to zero-out these rows that didn't have an 8.
[has8, col] = max(A == 8, [], 2);
% Zero out any rows that didn't contain an 8
result = has8 .* col;
% 0
% 0
% 4
% 0
% 4
% 0
% 3
% 3
% 3
% 0
If you'd rather have NaN's than 0's, you could do the following which exploits the fact that 0/0 == NaN
result = has8 .* col ./ has8;
% NaN
% NaN
% 4
% NaN
% 4
% NaN
% 3
% 3
% 3
% NaN
Inx = zeros(size(A,1),1); % initialize with default values
[row,col,v] = find(A==8); % find the proper indices
Inx(row) = col; % insert values

Find the rows of a matrix with conditions concerning the values of certain columns in matlab

As the title says, I want to find all rows in a Matlab matrix that in certain columns the values in the row are equal with the values in the previous row, or in general, equal in some row in the matrix. For example I have a matrix
1 2 3 4
1 2 8 10
4 5 7 9
2 3 6 4
1 2 4 7
and I want to find the following rows:
1 2 3 4
1 2 3 10
1 2 4 7
How do I do something like that and how do I do it generally for all the possible pairs in columns 1 and 2, and have equal values in previous rows, that exist in the matrix?
Here's a start to see if we're headed in the right direction:
>> M = [1 2 3 4;
1 2 8 10;
4 5 7 9;
2 3 6 4;
1 2 4 7];
>> N = M; %// copy M into a new matrix so we can modify it
>> idx = ismember(N(:,1:2), N(1,1:2), 'rows')
idx =
1
1
0
0
1
>> N(idx, :)
ans =
1 2 3 4
1 2 8 10
1 2 4 7
Then you can remove those rows from the original matrix and repeat.
>> N = N(~idx,:)
N =
4 5 7 9
2 3 6 4
this will give you the results
data1 =[1 2 3 4
1 2 8 10
4 5 7 9
2 3 6 4
1 2 4 7];
data2 = [1 2 3 4
1 2 3 10
1 2 4 7];
[exists,position] = ismember(data1,data2, 'rows')
where the exists vector tells you wheter the row is on the other matrix and position gives you the position...
a less elegant and simpler version would be
array_data1 = reshape (data1',[],1);
array_data2 = reshape (data2',[],1);
matchmatrix = zeros(size(data2,1),size(data1,1));
for irow1 = 1: size(data2,1)
for irow2 = 1: size(data1,1)
matchmatrix(irow1,irow2) = min(data2(irow1,:) == data1(irow2,:))~= 0;
end
end
the matchmatrix is to read as a connectivity matrix where value of 1 indicates which row of data1 matches with which row of data2

How to generate random matrix without repetition in rows and cols?

How to generate random matrix without repetition in rows and cols with specific range
example (3x3): range 1 to 3
2 1 3
3 2 1
1 3 2
example (4x4): range 1 to 4
4 1 3 2
1 3 2 4
3 2 4 1
2 4 1 3
A way of approaching this problem is to generate a circular matrix and shuffle it.
mat_size = 4
A = gallery('circul', 1:mat_size); % circular matrix
B = A( randperm(length(A)) , randperm(length(A)) ); % shuffle rows and columns with randperm
It gives
A =
1 2 3 4
4 1 2 3
3 4 1 2
2 3 4 1
B =
3 4 1 2
2 3 4 1
4 1 2 3
1 2 3 4
This method should be fast. An 11 size problem is computed in 0.047021 seconds.
This algorithm will do the trick, assuming you want to contain all elements between 1 and n
%// Elements to be contained, but no zero allowed
a = [1 2 3 4];
%// all possible permutations and its size
n = numel(a);
%// initialization
output = zeros(1,n);
ii = 1;
while ii <= n;
%// random permuation of input vector
b = a(randperm(n));
%// concatenate with already found values
temp = [output; b];
%// check if the row chosen in this iteration already exists
if ~any( arrayfun(#(x) numel(unique(temp(:,x))) < ii+1, 1:n) )
%// if not, append
output = temp;
%// increase counter
ii = ii+1;
end
end
output = output(2:end,:) %// delete first row with zeros
It definitely won't be the fastest implementation. I would be curios to see others.
The computation time increases exponentially. But everything up to 7x7 is bearable.
I wrote another code (interesting to compare timings and, if possible, to make it parallel). Also had problem with perms (needed to restart Matlab to be able to generate for 11 elements, I have x64 and 16GB of memory). Than I decided to keep characters instead of the numbers, reducing the memory occupied by the matrix. It, of course, generates all permutations, and I shuffle them in the beginning, selecting in the loop in a new random order. It runs faster this way and 'eats' less memory. Time for 11 x 11 (of course it differs from run to run) is shown in results.
clear all;
t = cputime;
sze = 11;
variations = perms(char(1 : sze)); % permutations
varN = length(variations);
variations = variations(randperm(varN)', :); % shuffle
sudoku = zeros(sze, sze);
sudoku(1, :) = variations(1, :); % set the first row
indx = 2;
for ii = 2 : varN
% take a random index
rowVal = variations(ii, :);
% check that row numbers do not present in table at
% corresponding columns
if (~isempty(find(repmat(rowVal, sze, 1) - sudoku == 0, 1)))
continue;
end;
sudoku(indx, :) = rowVal;
disp(['Found row ' num2str(indx)]);
indx = indx + 1;
if indx > sze, break; end;
end;
disp(cputime - t);
disp(sudoku);
Result
252.9712 seconds
7 11 3 9 6 2 4 1 8 10 5
1 9 6 3 10 7 11 5 2 4 8
9 6 11 8 2 10 1 7 4 5 3
4 10 7 11 1 8 5 2 6 3 9
2 5 9 1 3 6 8 4 10 7 11
10 3 5 6 7 4 2 9 11 8 1
6 4 2 10 8 5 3 11 9 1 7
3 8 10 4 11 1 7 6 5 9 2
11 1 8 5 4 9 6 3 7 2 10
5 2 4 7 9 3 10 8 1 11 6
8 7 1 2 5 11 9 10 3 6 4
Here's a memory-efficient approach. The time it takes is random, but not very large. All possible output matrices are equally likely.
This works by randomly filling the matrix until no more positions are available or until the whole matrix has been filled. The code is commented so it should be obvious how it works.
For size 11 this takes of the order of a few thousands or tens of thousands attempts. On my old laptop that means a (random) running time from a few seconds to tens of seconds.
It could perhaps be sped up using uint8 values instead of double. I don't think that brings a large gain, though.
The code:
clear all
n = 11; %// matrix size
[ ii jj ] = ndgrid(1:n); %// rows and columns of S
ii = ii(:);
jj = jj(:);
success = 0; %// ...for now
attempt = 0; %// attempt count (not really needed)
while ~success
attempt = attempt + 1;
S = NaN(n, n); %// initiallize result. NaN means position not filled yet
t = 1; %// number t is being placed within S ...
u = 1; %// ... for the u-th time
mask = true(1, numel(ii)); %// initiallize mask of available positions
while any(mask) %// while there are available positions
available = find(mask); %// find available positions
r = randi(numel(available), 1); %// pick one available position
itu = ii(available(r)); %// row of t, u-th time
jtu = jj(available(r)); %// col of t, u-th time
S(itu, jtu) = t; %// store t at that position
remove = (ii==itu) | (jj==jtu);
mask(remove) = false; %// update mask of positions available for t
u = u+1; %// next u
if u > n %// we are done with number t
t = t+1; %// let's go with new t
u = 1; %// initiallize u
mask = isnan(S(:)); %// initiallize mask for this t
end
if t > n %// we are done with all numbers
success = 1; %// exit outer loop (inner will be exited too)
end
end
end
disp(attempt) %// display number of attempts
disp(S) %// show result
An example result:
10 11 8 9 7 2 3 4 1 6 5
8 4 2 1 10 11 6 5 7 9 3
2 3 5 6 11 8 1 10 4 7 9
9 8 7 4 6 10 11 3 5 1 2
3 5 9 8 2 1 4 7 6 11 10
11 9 4 5 3 6 2 1 8 10 7
1 2 6 3 8 7 5 9 10 4 11
7 1 11 10 5 4 9 8 2 3 6
4 7 1 2 9 3 10 6 11 5 8
6 10 3 11 1 5 7 2 9 8 4
5 6 10 7 4 9 8 11 3 2 1

Rearranging matrix using col2im in Matlab

My matrix is this:
0 3 0
0 1 2
4 4 1
I use im2col on it like this:
im2col(A, [2 2], 'sliding')
which correctly yields this:
0 0 3 1
0 4 1 4
3 1 0 2
1 4 2 1
I call this matrix K. Now I use col2im to go back to my original matrix. From the Matlab documentation I use this:
col2im(K, [2 2], [5 5],'sliding')
But this doesn't gives me my original matrix A. Reason being [5 5] should be [4 4] to get a 3*3 matrix for starters. But when I do that I get
??? Error using ==> reshape
To RESHAPE the number of elements must not change.
Why is that? And how can I get my original matrix back?
Fromthe docs:
A = col2im(B,[m n],[mm nn],'sliding') rearranges the row vector B into
a matrix of size (mm-m+1)-by-(nn-n+1). B must be a vector of size
1-by-(mm-m+1)*(nn-n+1). B is usually the result of processing the
output of im2col(...,'sliding') using a column compression function
(such as sum).
So that says to me you should be trying something like:
col2im(sum(K), [2 2], [4 4],'sliding')
however that would require K to have 9 columns. I don't have the image processing toolbox handy to test this right now
Your col2im doesn't work because it uses reshape and for that the number of elements of the matrix you wish to reshape (K) and the new one, need to be the same. This is not the case anymore, as through your transformation of A with im2col you obviously changed that. A has 9 and K 16 elements.
So you basically need to get back to a 3*3 matrix again by getting rid of the redundand doubled elements (due to the overlapping 2*2 blocks used in im2col) in K.
For that you could just make a new matrix (C) with the elements that you need:
C = [K([1,3,11;2,4,12;6,8,16])]
As long as you first went from a 3*3 to a 4*4 matrix using the same order of blocks this should work.
Maybe you could tell us more about what you really want to achieve, because I don't see any reason for this in the first place. It may also be possible that you might be better off using other functions instead, but I can only see that if I know what the reasoning behind your question is.
clear
clc
img = double(imread('tire.tif'));
[r c] = size(img);
w = 8;
imgBlock = im2col(img,[w w],'sliding'); imgBlock = imgBlock(:);
[x y] = meshgrid(1:c,1:r);
xx = im2col(x,[w w], 'sliding'); xx = xx(:);
yy = im2col(y,[w w], 'sliding'); yy = yy(:);
img2 = accumarray([yy xx], imgBlock, [], #mean);
figure,imshow(img, []);
figure,imshow(img2,[]);
% random matrix as image
img = randi(10,4)
img =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
% matrix size
[r c] = size(img)
% patch size
w = 2;
% image to patch
imgBlock = im2col(img,[w w],'sliding')
% image patchs matrix to a vector
imgBlock = imgBlock(:);
r =
4
c =
4
imgBlock =
6 5 1 2 8 4 2 7 3
5 1 4 8 4 6 7 3 7
2 8 4 2 7 3 7 8 5
8 4 6 7 3 7 8 5 1
% index matrix size equal image size
[x y] = meshgrid(1:c,1:r)
% index matric to patchs;to vector
xx = im2col(x,[w w], 'sliding'); xx = xx(:);
yy = im2col(y,[w w], 'sliding'); yy = yy(:);
x =
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
y =
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
% yy :row index xx: column index
% applies the function mean to each subset of elements in imgBlock that have identical subscripts in [yy xx].
img2 = accumarray([yy xx], imgBlock, [], #mean);
img
img2
img =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
img2 =
6 2 2 7
5 8 7 8
1 4 3 5
4 6 7 1
% [col,row,value]
a = [xx,yy,imgBlock]
a =
1 1 6
1 2 5
2 1 2
2 2 8
1 2 5
1 3 1
2 2 8
2 3 4
1 3 1
1 4 4
2 3 4
2 4 6
2 1 2
2 2 8
3 1 2
3 2 7
2 2 8
2 3 4
3 2 7
3 3 3
2 3 4
2 4 6
3 3 3
3 4 7
3 1 2
3 2 7
4 1 7
4 2 8
3 2 7
3 3 3
4 2 8
4 3 5
3 3 3
3 4 7
4 3 5
4 4 1
% The number of times that img(2,2) occurs in the matrix img
a(xx == 2 & yy == 2,:)
ans =
2 2 8
2 2 8
2 2 8
2 2 8

Matlab: sorting a vector by the number of time each unique value occurs

We have p.e. i = 1:25 iterations.
Each iteration result is a 1xlength(N) cell array, where 0<=N<=25.
iteration 1: 4 5 9 10 20
iteration 2: 3 8 9 13 14 6
...
iteration 25: 1 2 3
We evaluate the results of all iterations to one matrix sorted according to frequency each value is repeated in descending order like this example:
Matrix=
Columns 1 through 13
16 22 19 25 2 5 8 14 17 21 3 12 13
6 5 4 4 3 3 3 3 3 3 2 2 2
Columns 14 through 23
18 20 1 6 7 9 10 11 15 23
2 2 1 1 1 1 1 1 1 1
Result explanation: Column 1: N == 16 is present in 6 iterations, column 2: N == 22 is present in 5 iterations etc.
If a number N isn't displayed (in that paradigm N == 4, N == 24) in any iteration, is not listed with frequency index of zero either.
I want to associate each iteration (i) to the first N it is displayed p.e. N == 9 to be present only in first iteration i = 1 and not in i = 2 too, N == 3 only to i = 2 and not in i = 25 too etc until all i's to be unique associated to N's.
Thank you in advance.
Here's a way that uses a feature of unique (i.e. that it returns the index to the first value) that was introduced in R2012a
%# make some sample data
iteration{1} = [1 2 4 6];
iteration{2} = [1 3 6];
iteration{3} = [1 2 3 4 5 6];
nIter= length(iteration);
%# create an index vector so we can associate N's with iterations
nn = cellfun(#numel,iteration);
idx = zeros(1,sum(nn));
idx([1,cumsum(nn(1:end-1))+1]) = 1;
idx = cumsum(idx); %# has 4 ones, 3 twos, 6 threes
%# create a vector of the same length as idx with all the N's
nVec = cat(2,iteration{:});
%# run `unique` on the vector to identify the first occurrence of each N
[~,firstIdx] = unique(nVec,'first');
%# create a "cleanIteration" array, where each N only appears once
cleanIter = accumarray(idx(firstIdx)',firstIdx',[nIter,1],#(x){sort(nVec(x))},{});
cleanIter =
[1x4 double]
[ 3]
[ 5]
>> cleanIter{1}
ans =
1 2 4 6
Here is another solution using accumarray. Explanations in the comments
% example data (from your question)
iteration{1} = [4 5 9 10 20 ];
iteration{2} = [3 8 9 13 14 6];
iteration{3} = [1 2 3];
niterations = length(iteration);
% create iteration numbers
% same as Jonas did in the first part of his code, but using a short loop
for i=1:niterations
idx{i} = i*ones(size(iteration{i}));
end
% count occurences of values from all iterations
% sort them in descending order
occurences = accumarray([iteration{:}]', 1);
[occ val] = sort(occurences, 1, 'descend');
% remove zero occurences and create the Matrix
nonzero = find(occ);
Matrix = [val(nonzero) occ(nonzero)]'
Matrix =
3 9 1 2 4 5 6 8 10 13 14 20
2 2 1 1 1 1 1 1 1 1 1 1
% find minimum iteration number for all occurences
% again, using accumarray with #min function
assoc = accumarray([iteration{:}]', [idx{:}]', [], #min);
nonzero = find(assoc);
result = [nonzero assoc(nonzero)]'
result =
1 2 3 4 5 6 8 9 10 13 14 20
3 3 2 1 1 2 2 1 1 2 2 1