Label segments based on percentage

Hi,
I have a variable (AL_128 which I have attached). It is a 1x48 cell where each cell is a Ax20 matrix. The matrices contain the values 0 and 1. For instance, cell 1 is a 225x20 matrix which should be interpret as follows: 225 segments where each segment is of length 20.
What I want to do here is to say that if 30% of the segments contain the label 1, the whole segment should be labelled 1. Therefore, cell 1 will end up being a 225x1 vector. This should be done for all segments and all cells.
How can I do that?

 Réponse acceptée

Guillaume
Guillaume le 18 Déc 2019
Modifié(e) : Guillaume le 18 Déc 2019
Much simpler code:
threshold = 0.3; %30% threshold
M = cellfun(@(m) mean(m, 1) >= threshold, AL_128, 'UniformOutput', false)
Or if you really want to use a loop over the cell array:
M = cell(size(AL_128));
for cidx = 1:numel(AL_128)
M{cidx} = mean(AL_128{cidx}, 1) >= threshold;
end
There is certainly no need to loop over the columns of the matrix.

1 commentaire

Uerm
Uerm le 23 Déc 2019
Thanks a lot, both of you!
In my case it would be
threshold = 0.3; %30% threshold
M = cellfun(@(m) mean(m, 2) >= threshold, AL_128, 'UniformOutput', false)
as I do the calculation along the rows.

Connectez-vous pour commenter.

Plus de réponses (1)

Image Analyst
Image Analyst le 13 Déc 2019
Your data didn't seem to have any segments where the value was 1, at least in the several cells I looked in, but I think this should work and be pretty easy to follow and understand.
s = load('AL_128.mat')
AL_128 = s.AL_128
% Define output cell array
output = cell(size(AL_128));
for k = 1 : length(AL_128)
% Get the contents of this cell
thisCellsContents = AL_128{k}; % This is an N rows - by - 20 columns matrix.
[rows, columns] = size(thisCellsContents); % Get the number of rows and columns in this matrix.
% See which rows contain a 1 in any column
containsA1 = any(thisCellsContents == 1, 2); % This is a N row vector.
% See if the number of them is 30% or more of the rows
fractionContaining1 = sum(containsA1) / rows;
if fractionContaining1 >= 0.3
output{k} = ones(rows, 1); % Make vector of all 1's
else
output{k} = thisCellsContents; % Just the original contents.
end
end
% Overwrite input, if desired.
AL_128 = output

10 commentaires

Uerm
Uerm le 15 Déc 2019
Modifié(e) : Uerm le 15 Déc 2019
Hi, thanks a lot.
I tried the code, but each cell does not end up being a Bx1 vector. It rather gives me the same 225x20 matrix etc. for each cell...
Should I use mode(output,2) on the output of your code?
I think that's because, as I said, there are no 1's in your any of your matrices, so the criteria of the "if" never got satisfied and so this statement never got executed:
output{k} = ones(rows, 1); % Make vector of all 1's
so no vector ever got created. If you do have a cell array where some cells contain a matrix where at least 30% of the rows contain a 1, then attach it and I'll check it.
Uerm
Uerm le 15 Déc 2019
Hi again,
I believe cell number 25 has a lot of 1's (in the original .mat file I attached). I have tried to use mode(output,2) after running your code and it generates more 1 labels than just using model(AL_128,2).
Maybe I should use mode(output,2) after your code... As I understand your code, say 40 % of one row is labelled 1, then it generates ones so that the whole row is filled with ones (the original zeros become ones). Then computing the mode of this row will generate one value, which in this case would be 1.
Uerm
Uerm le 15 Déc 2019
Modifié(e) : Uerm le 15 Déc 2019
I don't think the code generates what I want. The code should look at each individual row of each cell. Each row is considered a segment. If a segment contains at least 30% 1's, then the whole segment should be 1. If not, the whole segment should be labelled 0. That is why the 225x20 matrix (225 segments of length 20) should end as a 225x1 vector.
So "Each row is considered a segment. If a segment contains at least 30% 1's, then the whole segment should be 1." meaning the whole row should be 1, meaning the matrix is the same size, just that certain rows (where more than 30% of the values are 1) should be all 1's.
That's not what I did. I made a column vectors, except in those cases where not more than 30% were 1's and in that case I left the matrix alone. But you also said "should end as a 225x1 vector". So I think your statements are contradictory and I don't know whether you want segments/rows to be set to all 1 in the existing matrix, or if you want a vector where only some elements are 1 (where the row is 30% or more with 1's). I also don't know what you want to do with the existing matrices where the 30% criteria is not met. I just left those alone, but is that what you want?
If you put in an fprintf statement
s = load('AL_128.mat')
AL_128 = s.AL_128
% Define output cell array
output = cell(size(AL_128));
for k = 1 : length(AL_128)
% Get the contents of this cell
thisCellsContents = AL_128{k}; % This is an N rows - by - 20 columns matrix.
[rows, columns] = size(thisCellsContents); % Get the number of rows and columns in this matrix.
% See which rows contain a 1 in any column
containsA1 = any(thisCellsContents == 1, 2); % This is a N row vector.
% See if the number of them is 30% or more of the rows
fractionContaining1 = sum(containsA1) / rows;
if fractionContaining1 >= 0.3
fprintf('Setting cell #%d to a %d-row column vector\n', k, rows);
output{k} = ones(rows, 1); % Make vector of all 1's
else
output{k} = thisCellsContents; % Just the original contents.
end
end
% Overwrite input, if desired.
AL_128 = output
then you'll see
Setting cell #25 to a 186-row column vector
Setting cell #26 to a 210-row column vector
Setting cell #27 to a 277-row column vector
Setting cell #32 to a 261-row column vector
Setting cell #38 to a 213-row column vector
Setting cell #40 to a 239-row column vector
so I made those cells into vectors.
If on the other hand you want to replace the matrix in each cell with a vector where it's one if more than 30% in that particular row are 1, and zero where less than 30% are 1, then run this code:
s = load('AL_128.mat')
AL_128 = s.AL_128
% Define output cell array
output = cell(size(AL_128));
for k = 1 : length(AL_128)
% Get the contents of this cell
thisCellsContents = AL_128{k}; % This is an N rows - by - 20 columns matrix.
[rows, columns] = size(thisCellsContents); % Get the number of rows and columns in this matrix.
% See which rows contain a 1 in any column
num1sPerRow = sum(thisCellsContents == 1, 2); % This is a N row vector.
% See if the number of them is 30% or more of the columns.
fractionContaining1 = num1sPerRow / columns;
if fractionContaining1 >= 0.3
fprintf('Setting cell #%d to a %d-row column vector\n', k, rows);
vec = zeros(rows, 1); % Initialize.
vec(fractionContaining1 > 0.3 * columns) = 1; % Set certain rows to 1.
output{k} = vec; % Make vector of 0's and 1's
else
output{k} = thisCellsContents; % Just the original contents.
end
end
% Overwrite input, if desired.
% AL_128 = output
You'll see
Setting cell #32 to a 261-row column vector
Setting cell #40 to a 239-row column vector
But again, I'm not sure if you want matrices or vectors. You've said it both ways. And I've given two ways of doing it. If neither is what you want then you'll just have to give an example and explain it. And have some cases where the matrices are a mix of 0s and 1s, not all 0 or 1 like you have now.
Uerm
Uerm le 15 Déc 2019
Sorry for the confusion.
Let me say it this way, this might clarify things:
The original variable, AL_128 is a 1x48 cell where each cell is a Ax20 matrix. By just running the code
M = cellfun(@(m)mode(m,2), AL_128,'uni',0);
I end with each cell being a Ax1 vector instead. What the code does it that it looks at the most frequent value along the rows. With mode, the threshold is 50%. Therefore, if 50% or more of a segment is labelled 1, the whole segment will be labelled 1. Otherwise, the segment label will be 0.
I want to run exactly the same code, but instead of the threshold of 50%, this threshold should be 30%. If minimum 30% of a segment is 1, then the whole segment is 1, otherwise 0.
Hope it makes sense.
Image Analyst
Image Analyst le 15 Déc 2019
And didn't my second chunk of code in my last comment do that?
Again, please attach your actual matrix.
And say what you want to happen with the cell contents if the 30% criteria is not met. Do you want the original A-by-20 matrix, or do you want some kind of column vector for that case also?
Uerm
Uerm le 15 Déc 2019
Modifié(e) : Uerm le 16 Déc 2019
Unfortunately, the second chunk did not do that. I attach the original variable (AL_128) and the result of running mode(AL_128,2), which is called M.mat. As you can see, all the cells end being vectors containing 0 and 1. Please look at cell 25-26 as they contain a lot of 1's and 0's.
Does it make sense?
When the criteria is met, the label is 1. If not, the label is 0.
I have also attached an image for better understanding. The image shows an example where the segment length is 10.
OK, the picture helped. Try this:
s = load('AL_128.mat')
AL_128 = s.AL_128
% Define output cell array
output = cell(size(AL_128));
for k = 1 : length(AL_128)
% Get the contents of this cell
thisCellsContents = AL_128{k}; % This is an N rows - by - 20 columns matrix.
[rows, columns] = size(thisCellsContents); % Get the number of rows and columns in this matrix.
% See which rows contain a 1 in any column
num1sPerRow = sum(thisCellsContents == 1, 2); % This is a N row vector.
% See if the number of them is 30% or more of the columns.
fractionContaining1 = num1sPerRow / columns;
fprintf('The highest fraction of ones any row in matrix #%d has is %.2f.\n', k, max(fractionContaining1));
% Say what rows need to be set to 1 and which need to be set to zero.
indexesToSetTo1 = fractionContaining1 > 0.3;
if any(indexesToSetTo1)
fprintf('Setting cell #%d to a %d-row column vector\n', k, rows);
output{k} = indexesToSetTo1; % Make vector of 0's and 1's
else
fprintf('Leaving cell #%d alone.\n', k);
output{k} = thisCellsContents; % Just the original contents.
end
end
% Overwrite input, if desired.
% AL_128 = output
Uerm
Uerm le 18 Déc 2019
Thanks a lot! I found that this works too:
function M = threshold(AL_128,n)
for i = 1:length(AL_128)
for k = 1:size(AL_128{1,i},1)
M{i}(k,:) = double(mean(AL_128{1,i}(k,:))>=(n/100));
end
end

Connectez-vous pour commenter.

Produits

Version

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by