I have a function which finds the ROWS in an array having repeating number and replaces them by the a unique row.
Here is the function:
NVAR= number of parameter in the unique row
PVBu= upper bound of the numbers in the row
lower bound is 1 by default
function [A]=nonrepeatuniquerow(A,NVAR,PVBu)
HM = zeros(1,NVAR);
p = zeros(1,PVBu);
for j = 1
p(1:PVBu) = 1:PVBu;
for k = PVBu:-1:PVBu-NVAR+1
q = ceil(k*rand);
HM(j,PVBu-k+1) = p(q);
p(q:k-1) = p(q+1:k);
end
end
b = any(~diff(sort(A,2),1,2),2) | any(A==0,2);
A(b,:) = repmat(HM,sum(b),1);
end
For example,
Assume [9 1 7] is the unique randomly generated row.
Matrix A is passed to the function 'nonrepeatuniquerow'.
A= [2 3 3
2 5 2
1 5 9
9 7 6]
And output is:
A= [9 1 7
9 1 7
1 5 9
9 7 6]
My question is how to modify the function so that it replaces the ROWS having a repeating number by DIFFERENT unique rows ?
For example the output could be as follows:
A= [7 2 3
2 1 8
1 5 9
9 7 6]
The function below only generates unique rows every time it is called.
NVAR=number of parameter in the unique row
PVBu= upper bound of the numbers in the row
lower bound is 1 by default
function [HM]=generateunique(NVAR,PVBu)
HM = zeros(1,NVAR);
p = zeros(1,PVBu);
for j = 1
p(1:PVBu) = 1:PVBu;
for k = PVBu:-1:PVBu-NVAR+1
q = ceil(k*rand);
HM(j,PVBu-k+1) = p(q);
p(q:k-1) = p(q+1:k);
end
end
end
I would greatly appreciate any help you can give me in working this problem?
In the function nonrepeatuniquerow, the first part is just for creating the random sequence HM. You could run through all non-unique rows in a for loop and create a separate HM for each. That would look like this:
function [A]=nonrepeatuniquerow(A,NVAR,PVBu)
b = any(~diff(sort(A,2),1,2),2) | any(A==0,2);
for ii=find(b==1).'
HM = zeros(1,NVAR);
p = zeros(1,PVBu);
for j = 1
p(1:PVBu) = 1:PVBu;
for k = PVBu:-1:PVBu-NVAR+1
q = ceil(k*rand);
HM(j,PVBu-k+1) = p(q);
p(q:k-1) = p(q+1:k);
end
end
A(ii,:) = HM;
end
end
You could also replace the generateunique function or the part which does the same in your code by the built-in randperm function. You can create a unique random sequence by
HM = randperm(PVBu,NVAR);
that would give you the following code
function A = nonrepeatuniquerow(A,NVAR,PVBu)
b = any(~diff(sort(A,2),1,2),2) | any(A==0,2);
for ii=find(b==1).'
A(ii,:) = randperm(PVBu,NVAR);
end
end
Related
I have a matrix D of distances between 3 places and 4 persons
example D(2,3) = 10 means person 3 is far away from place 2 of 10 units.
D=[23 54 67 32
32 5 10 2
3 11 13 5]
another matrix A with the same number of rows (3 places) and where A(i,:) correspond to the persons that picked place i
example for place 1, persons 1 and 3 picked it
no one picked place 2
and persons 2 and 4 picked place 3
A=[1 3 0
0 0 0
2 4 0]
I want to reorder each row of A by the persons who are closest to the place it represents.
In this example, for place 1, person 1 is closer to it than person 3 based on D so nothing to do.
nothing to do for place 2
and there is a change for place 3 since person 4 is closer than 2 to place 3 D(3,2)>D(3,4)
The result should be
A=[1 3
0 0
4 2 ]
each row(place) in A can have 0 or many non zeros elements in it (persons that picked it)
Basically, I want to reorder elements in each row of A based on the rows of D (the closest to the location comes first), something like this but here A and D are not of the same size (number of columns).
[SortedD,Ind] = sort(D,2)
for r = 1:size(A,1)
A(r,:) = A(r,Ind(r,:));
end
There is another Matlab function sortrows(C,colummn_index) that can do the trick. It can sort rows based on the elements in a particular column. So if you transpose your matrix A (C = A') and extend the result by adding to the end the proper column, according to which you want to sort a required row, then you will get what you want.
To be more specific, you can do something like this:
clear all
D=[23 54 67 32;
32 5 10 2;
3 11 13 5];
A=[1 0;
3 0;
4 2 ];
% Sort elements in each row of the matrix A,
% because indices of elements in each row of the matrix D are always
% ascending.
A_sorted = sort(A,2);
% shifting all zeros in each row to the end
for i = 1:length(A_sorted(:,1))
num_zeros = sum(A_sorted(i,:)==0);
if num_zeros < length(A_sorted(i,:))
z = zeros(1,num_zeros);
A_sorted(i,:) = [A_sorted(i,num_zeros+1:length(A_sorted(i,:))) z];
end;
end;
% Prelocate in memory an associated array of the corresponding elements in
% D. The matrix Dr is just a reduced derivation from the matrix D.
Dr = zeros(length(A_sorted(:,1)),length(A_sorted(1,:)));
% Create a matrix Dr of elements in D corresponding to the matrix A_sorted.
for i = 1:length(A_sorted(:,1)) % i = 1:3
for j = 1:length(A_sorted(1,:)) % j = 1:2
if A_sorted(i,j) == 0
Dr(i,j) = 0;
else
Dr(i,j) = D(i,A_sorted(i,j));
end;
end;
end;
% We don't need the matrix A_sorted anymore
clear A_sorted
% In order to use the function SORTROWS, we need to transpose matrices
A = A';
Dr = Dr';
% The actual sorting procedure starts here.
for i = 1:length(A(1,:)) % i = 1:3
C = zeros(length(A(:,1)),2); % buffer matrix
C(:,1) = A(:,i);
C(:,2) = Dr(:,i);
C = sortrows(C,2);
A(:,i) = C(:,1);
% shifting all zeros in each column to the end
num_zeros = sum(A(:,i)==0);
if num_zeros < length(A(:,i))
z = zeros(1,num_zeros);
A(:,i) = [A(num_zeros+1:length(A(:,i)),i) z]';
end;
end;
% Transpose the matrix A back
A = A';
clear C Dr z
I have a vector : for example S=(0,3,2,0,1,2,0,1,1,2,3,3,0,1,2,3,0).
I want to count co-occurrence neighbors, for example the first neighbor "o,3" how many times did it happen till the end of the sequence? Then it investigates the next pair"2,0" and similarly do it for other pairs.
Below is a part of my code:
s=size(pic);
S=s(1)*s(2);
V = reshape(pic,1,S);
min= min(V);
Z=zeros(1,S+1);
Z(1)=min;
Z(2:end)=V;
for i=[0:2:length(Z)-1];
contj=0
for j=0;length(Z)-1;
if Z(i,i+1)= Z(j,j+1)
contj=contj+1
end
end
count(i)= contj
end
It gives me this error:
The expression to the left of the equals sign is not a valid target for an assignment
in this line:
if Z(i,i+1)= Z(j,j+1)
I read similar questions and apply the tips on it but they didn't work!
If pairs are defined without overlapping (according to comments):
S = [0,3,2,0,1,2,0,1,1,2,3,3,0,1,2,3]; %// define data
S2 = reshape(S,2,[]).'; %'// arrange in pairs: one pair in each row
[~, jj, kk] = unique(S2,'rows'); %// get unique labels for pairs
pairs = S2(jj,:); %// unique pairs
counts = accumarray(kk, 1); %// count of each pair. Or use histc(kk, 1:max(kk))
Example: with S as above (I introduce blanks to make pairs stand out),
S = [0,3, 2,0, 1,2, 0,1, 1,2, 3,3, 0,1, 2,3];
the result is
pairs =
0 1
0 3
1 2
2 0
2 3
3 3
counts =
2
1
2
1
1
1
If pairs are defined without overlapping but counted with overlapping:
S = [0,3,2,0,1,2,0,1,1,2,3,3,0,1,2,3]; %// define data
S2 = reshape(S,2,[]).'; %'// arrange in pairs: one pair in each row
[~, jj] = unique(S2,'rows'); %// get unique labels for pairs
pairs = S2(jj,:); %// unique pairs
P = [S(1:end-1).' S(2:end).']; %// all pairs, with overlapping
counts = sum(pdist2(P,pairs,'hamming')==0);
If you don't have pdist2 (Statistics Toolbox), replace last line by
counts = sum(all(bsxfun(#eq, pairs.', permute(P, [2 3 1]))), 3);
Result:
>> pairs
pairs =
0 1
0 3
1 2
2 0
2 3
3 3
>> counts
counts =
3 1 3 2 2 1
do it using sparse command
os = - min(S) + 1; % convert S into indices
% if you want all pairs, i.e., for S = (2,0,1) count (2,0) AND (0,1):
S = sparse( S(1:end-1) + os, S(2:end) + os, 1 );
% if you don't want all pairs, i.e., for S = (2,0,1,3) count (2,0) and (1,3) ONLY:
S = sparse( S(1:2:end)+os, S(2:2:end) + os, 1 );
[f s c] = find(S);
f = f - os; % convert back
s = s - os;
co-occurences and their count are in the pairs (f,s) - c
>> [f s c]
ans =
2 0 2 % i.e. the pair (2,0) appears twice in S...
3 0 2
0 1 3
1 1 1
1 2 3
3 2 1
0 3 1
2 3 2
3 3 1
I am trying to write a function that sums the previous n elements for each the element
v = [1 1 1 1 1 1];
res = sumLastN(v,3);
res = [0 0 3 3 3 3];
Until now, I have written the following function
function [res] = sumLastN(vec,ppts)
if iscolumn(vec)~=1
error('First argument must be a column vector')
end
sz_x = size(vec,1);
res = zeros(sz_x,1);
if sz_x > ppts
for jj = 1:ppts
res(ppts:end,1) = res(ppts:end,1) + ...
vec(jj:end-ppts+jj,1);
end
% for jj = ppts:sz_x
% res(jj,1) = sum(vec(jj-ppts+1:jj,1));
% end
end
end
There are around 2000 vectors of about 1 million elements, so I was wondering if anyone could give me any advice of how I could speed up the function.
Using cumsum should be much faster:
function [res] = sumLastN(vec,ppts)
w=cumsum(vec)
res=[zeros(1,ppts-1),w(ppts+1:end)-w(1:end-ppts)]
end
You basically want a moving average filter, just without the averaging.
Use a digital filter:
n = 3;
v = [1 1 1 1 1 1];
res = filter(ones(1,n),1,v)
res =
1 2 3 3 3 3
I don't get why the first two elements should be zero, but why not:
res(1:n-1) = 0
res =
0 0 3 3 3 3
I have a matrix sorted in ascending order.
S = 25;
RT = zeros(S,2);
for i = 1:S;
for j = 1:i;
R = i *j;
T = R + j;
RT(j,:) = [R T];
end
end
sortRT = sortrows(RT, [1 2]);
disp(sortRT);
I want to find the sortRT elements which values is lower than 500 (for R) and 490 (for T) per column and place these values inside a matrix. Is it possible?
Just use find:
idx = find(sortRT(:,1)<500 & sortRT(:,2)<490)
idx' =
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
These are the rows where both R<500 and T<490. You can of course separate these two:
idxR500 = find(sortRT(:,1)<500);
idxT490 = find(sortRT(:,2)<490);
If you're just going to copy elements or rows, then find isn't even necessary and you can use logical indexing:
R500 = sortRT(find(sortRT(:,1)<500) , 1);
is the same as
R500 = sortRT(sortRT(:,1)<500 , 1);
This copies elements of the first column, if you want to copy the whole row, use the colon operator:
R500 = sortRT(sortRT(:,1)<500 , :);
How to repeat
A = [ 1 2 ;
3 4 ]
repeated by
B = [ 1 2 ;
2 1 ]
So I want my answer like matrix C:
C = [ 1 2 2;
3 3 4 ]
Thanks for your help.
Just for the fun of it, another solution making use of arrayfun:
res = cell2mat(arrayfun(#(a,b) ones(b,1).*a, A', B', 'uniformoutput', false))'
This results in:
res =
1 2 2
3 3 4
To make this simple, I assume that you're only going to add more columns, and that you've checked that you have the same number of columns for each row.
Then it becomes a simple combination of repeating elements and reshaping.
EDIT I've modified the code so that it also works if A and B are 3D arrays.
%# get the number of rows from A, transpose both
%# A and B so that linear indexing works
[nRowsA,~,nValsA] = size(A);
A = permute(A,[2 1 3]);
B = permute(B,[2 1 3]);
%# create an index vector from B
%# so that we know what to repeat
nRep = sum(B(:));
repIdx = zeros(1,nRep);
repIdxIdx = cumsum([1 B(1:end-1)]);
repIdx(repIdxIdx) = 1;
repIdx = cumsum(repIdx);
%# assemble the array C
C = A(repIdx);
C = permute(reshape(C,[],nRowsA,nValsA),[2 1 3]);
C =
1 2 2
3 3 4