Applying grouping to values greater than average - matlab

I have a vector where I want to group based on the rolling average of the values in my vector. If the values are greater than average than I place them in group 1, if they are less they go in group 2.
What function can be used to give a group number to each to value within my vector based on whether or not its value is greater than the current average.

I don't think there is a function to assign "labels" to array entries.
Assuming v is your input vector, an easy approach would be to simply do:
v(v>mean(v)) %Group 1
v(v<mean(v)) %Group 2
If you intend on doing more with it of course, you could do the following:
avg = mean(v);
flag = zeros(size(v));
for i=1:numel(v)
if(v(i)>avg)
flag(i) = 1;
else
flag(i) = 2;
end
end
flag would contain your requisite grouping. Now if you want the elements of v in group 1, you can simply use:
v(flag==1)
If you want a rolling average though, it depends on how you compute it, but the same basic method should suffice.

There's no simple function that will do that. You'll need something like this:
N = length(vec);
[lo_group hi_group] = deal( NaN(ceil(N/2),1) );
[sum lo_ct hi_ct] = deal(0);
for i=1:N
v = vec(i);
sum = sum + v;
avg = sum/i;
if v>avg
hi_ct = hi_ct + 1;
hi_group(hi_ct) = v;
else
lo_ct = lo_ct + 1;
lo_group(lo_ct) = v;
end
end

Related

Conditional Split arrays within a cell

Assume I have a 50x1 cell(say Q) with column matrices of varying dimensions (say 1568936x1 , 88x1,5040x1 ) etc
losing values isn't an issue. I need all the matrices inside the cell to be divisible by said number (say 500) so like 1568500x1 , 5000x1 skipping over 88x1 etc.
Currently I have:
z=cell(length(Q),1)
for p=1:length(z)
n=length(Q{p})
for w=1:length(z)
if n-mod(length(Q{w}),500)<500
w=w+1;
else
o=length(Q{w}-mod(length(Q{w}),500));
for k=1:length(z)
z=Q{w}((1:o));
end
end
end
end
but when I reach the 88x1 matrix it throws a dimensions exceeded error although I think I have covered that with the if condition where it should skip the matrix and move on to the next cell.
This should work fine:
Q = {
rand(58,1);
rand(168,1);
rand(33,1);
rand(199,1);
rand(100,1)
};
Q_len = numel(Q);
K = 50;
Z = cell(Q_len,1);
for i = 1:Q_len
Qi = Q{i};
Qi_len = numel(Qi);
k = floor(Qi_len / K) * K
Z{i} = Qi(1:k);
end
Given the starting vectors (shortened down in order to avoid excessive overloads), the final output Z is:
>> cellfun(#numel,Z)
ans =
50
150
0
150
100
If you want a shorter, one-liner version, here is one:
Q = {
rand(58,1);
rand(168,1);
rand(33,1);
rand(199,1);
rand(100,1)
};
K = 50;
Z = cellfun(#(x)x(1:(floor(numel(x)/K)*K)),Q,'UniformOutput',false);

Undertanding a low pass filter code in image processing

The aim of this piece of Matlab code is to smooth a horizontal histogram by applying a low pass filter.
First horizontal and vertical histograms representing the sum of differences of gray values between neighboring pixels of an image, column-wise and row-wise were used. The horizontal histogram is named horz1 so horz1(i)=sum where 'i' is the column number and 'sum' is the sum of differences. Then, a low pass filter was applied. I don't understand the 'applying low pass filter' part.I don't know much about Image processing. If anyone could help me understand I would really appreciate it.
%% horizontal histogram
disp('Processing Edges Horizontally...');
max_horz = 0;
maximum = 0;
for i = 2:cols
sum = 0;
for j = 2:rows
if(I(j, i) > I(j-1, i))
difference = uint32(I(j, i) - I(j-1, i));
else
difference = uint32(I(j-1, i) - I(j, i));
end
if(difference > 20)
sum = sum + difference;
end
end
horz1(i) = sum;
%%applying low pass filter
sum = 0;
horz = horz1;
for i = 21:(cols-21)
sum = 0;
for j = (i-20):(i+20)
sum = sum + horz1(j);
end
horz(i) = sum / 41;
end
end
It simply finds the average over a 41 element window. Low-pass filter retains low-frequency components and suppresses high frequency components. Averaging is an example of a low-pass filter.
The explanation of the two for loops at the end when calculating the filtered output is as follows. It starts at i = 21 because it needs to collect 20 values before and after without going out of bounds including the middle: 20 + 20 + 1 = 41. When i = 21, then j = 1 to 41, then when i = 22, j = 2 to 42 etc. up to cols - 21, which is thus j = cols - 41 up to cols - 1. Technically we should end at i = cols - 20 though, but that's ok if you want to miss calculating the final valid output of the signal.
The loop controlled by i determines what the centre of the window is and the loop controlled by j collects the right samples dictated by i. You'll need to think about it especially if you aren't used to this, but eventually it will make sense.

Matlab unique function

I'm struggling with determining the probability of occurrence of unique elements in thresh_strain matrix (which can be seen below as a 100 x 16). I was trying to use the code at the bottom to do this, but I get an equal probability of occurrence associated with each of the elements, whereas I want the probability of occurrence associated with unique elements in thresh_strain.
function [thresh_strain] = MCsolution()
no_iterations = 100;
thresh_strain = zeros(100, 16);
casechoice =input('Enter 1 for 1st Layup and 2 for 2nd layup:');
for i=1:no_iterations
for j=1:16
J = Nielsennew(casechoice);
thresh_strain(i,j) = J(1, j);
end
end
% [uniqueValues,~,uniqueIndex] = unique(thresh_strain);
% frequency = accumarray(uniqueIndex(:),1)./numel(thresh_strain);
Thanks
It is not really clear from the title and description, but I suppose you may be looking for something like this:
myUniqueValues = unique(myMatrix);
nelements = hist(myMatrix(:),myUniqueValues);
%plot(myUniqueValues,nelements)
Basically calculating how often each unique value occurs. From here getting the corresponding percentage is of course trivial.

How can I rearrange a list of numbers so that every N numbers is nonrepeating?

So I have a list of 190 numbers ranging from 1:19 (each number is repeated 10 times) that I need to sample 10 at a time. Within each sample of 10, I don't want the numbers to repeat, I tried incorporating a while loop, but computation time was way too long. So far I'm at the point where I can generate the numbers and see if there are repetitions within each subset. Any ideas?
N=[];
for i=1:10
N=[N randperm(19)];
end
B=[];
for j=1:10
if length(unique(N(j*10-9:j*10)))<10
B=[B 1];
end
end
sum(B)
Below is an updated version of the code. this might be a little more clear in showing what I want. (19 targets taken 10 at a time without repetition until all 19 targets have been repeated 10 times)
nTargs = 19;
pairs = nchoosek(1:nTargs, 10);
nPairs = size(pairs, 1);
order = randperm(nPairs);
values=randsample(order,19);
targs=pairs(values,:);
Alltargs=false;
while ~Alltargs
targs=pairs(randsample(order,19),:);
B=[];
for i=1:19
G=length(find(targs==i))==10;
B=[B G];
end
if sum(B)==19
Alltargs=true;
end
end
Here are some very simple steps to do this, basically you just shuffle the vector once, and then you grab the last 10 unique values:
v = repmat(1:19,1,10);
v = v(randperm(numel(v)));
[a idx]=unique(v);
result = unique(v);
v(idx)=[];
The algorithm should be fairly efficient, if you want to do the next 10, just run the last part again and combine the results into a totalResult
You want to sample the numbers 1:19 randomly in blocks of 10 without repetitions. The Matlab function 'randsample' has an optional 'replacement' argument which you can set to 'false' if you do not want repetitions. For example:
N = [];
replacement = false;
for i = 1:19
N = [N randsample(19,10,replacement)];
end
This generates a 19 x 10 matrix of random integers in the range [1,..,19] without repetitions within each column.
Edit: Here is a solution that addresses the requirement that each of the integers [1,..,19] occurs exactly 10 times, in addition to no repetition within each column / sample:
nRange = 19; nRep = 10;
valueRep = true; % true while there are repetitions
nLoops = 0; % count the number of iterations
while valueRep
l = zeros(1,nRep);
v = [];
for m = 1:nRep
v = [v, randperm(nRange,nRange)];
end
m1 = reshape(v,nRep,nRange);
for n = 1:nRep
l(n) = length(unique(m1(:,n)));
end
if all(l == nRep)
valueRep = false;
end
nLoops = nLoops + 1;
end
result = m1;
For the parameters in the question it takes about 300 iterations to find a result.
I think you should approach this constructively.
It's easy to initially find a 19 groups that fulfill your conditions just by rearranging the series 1:19: series1 = repmat(1:19,1,10); and rearranged= reshape(series1,10,19)
then shuffle the values
I would select two random columns copy them and switch the values at two random positions
then make a test if it fulfills your condition - like: test = #(x) numel(unique(x))==10 - if yes replace your columns
just keep shuffling till your time runs out or you are happy
of course you might come up with more efficient shuffling or testing
I was given another solution through the MATLAB forum that works pretty well (Credit to Niklas Nylen over on the MATLAB forum). Computation time is pretty low too. It basically shuffles the numbers until there are no repetitions within every 10 values. Thanks all for your help.
y = repmat(1:19,1,10);
% Run enough iterations to get the output random enough, I selected 100000
for ii = 1:100000
% Select random index
index = randi(length(y)-1);
% Check if it is allowed to switch places
if y(index)~=y(min(index+10, length(y))) && y(index+1)~=y(max(1,index-9))
% Make the switch
yTmp = y(index);
y(index)=y(index+1);
y(index+1)=yTmp;
end
end

Compute the convolution of two arrays in MATLAB

I am trying to generate an array from some starting values using this formula in MATLAB:
yt = a0 + ∑i=1p (ai ⋅ yt-i), t ≥ p
p is some small number compared to T (max t). I have been able to make this using two for cycles but it is really slow. Is there some easy way to do it?
First p values of y are provided and vector a (its length is p+1) is provided too...
This is what I have so far, but now when I tried it, it doesn't work 100% (I think it's because of indexing from 1 in MATLAB):
y1 = zeros(T+1, 1);
y1(1:p) = y(1:p);
for t = p+1:T+1
value = a1(1);
for j = 2:p+1
value = value + a1(j)*y1(t-j+1);
end
y1(t) = value;
end
EDIT: I solved it, I am just not used to Matlab indexing from 1...
This statement
if(p>=t)
looks odd inside a loop whose index expression is
for t = p+1:T+1
which seems to guarantee that t>p for the entire duration of the loop. Is that what you meant to write ?
EDIT in response to comment
Inside a loop indexed with this statement
for j = 2:p
how does the reference you make to a(j) ever call for a(0) ?
y1 = zeros(T+1, 1);
y1(1:p) = y(1:p);
for t = p+1:T+1
value = a1(1);
for j = 2:p+1
value = value + a1(j)*y1(t-j+1);
end
y1(t) = value;
end