Delete determinate rows in a matrix - arrays

I have an array like this but with more rows:
104,206 99,557 96,667 1 33 1 120,993 0
104,708 99,189 96,641 6 14 1 123,989 65536
107,099 102,732 98,641 0 46 1 118,899 131072
104,985 101,174 98,251 5 30 2 118,445 196608
108,86 103,355 103,494 0 21 1 118,423 262144
I need a loop which delete all the rows when in the 4th column is a 0.
I need do this with all the rows and the result is as follows:
104,206 99,557 96,667 1 33 1 120,993 0
104,708 99,189 96,641 6 14 1 123,989 65536
104,985 101,174 98,251 5 30 2 118,445 196608

In a single line (using logical indexing):
data(data(:,4)==0,:) = [];
Example:
>> data = [5 8 6 0 9
1 3 3 5 2
4 5 6 0 8
2 2 7 3 5];
>> data(data(:,4)==0,:) = []
data =
1 3 3 5 2
2 2 7 3 5

data = randi(10,1000,10) -1; % random data
marks = find(data(:,4)); % find only returns non-zero elements
clean_data = data(marks,:); % return all data on row /marks/

Related

Problems with setting array elements in Forth

I am writing code in Forth that should create a 12x12 array of random numbers from 1 to 8.
create big_array 144 allocate drop
: reset_array big_array 144 0 fill ;
reset_array
variable rnd here rnd !
: random rnd # 31421 * 6927 + dup rnd ! ;
: choose random um* nip ;
: random_fill 144 1 do 8 choose big_array i + c! loop ;
random_fill
: Array_# 12 * + big_array swap + c# ;
: show_small_array cr 12 0 do 12 0 do i j Array_# 5 u.r loop cr loop ;
show_small_array
However, I notice that elements 128 to 131 of my array are always much larger than expected:
0 4 0 4 2 6 0 5 2 5 7 3
6 3 7 3 7 7 3 1 5 0 6 1
0 3 3 0 3 1 0 7 2 0 4 5
3 7 6 6 2 1 0 2 3 4 2 7
4 7 1 5 3 5 7 2 3 5 3 6
3 0 6 4 1 3 3 2 5 4 4 7
3 2 1 4 3 4 3 7 2 6 5 5
2 4 4 3 4 5 4 4 6 5 6 0
2 5 2 7 3 1 5 0 1 4 6 7
2 0 3 3 0 7 3 6 4 1 3 6
0 1 1 6 0 3 0 2 169 112 41 70
7 2 3 1 2 2 7 6 0 5 1 2
Moreover, when I try to change the value of these elements individually, this causes the other three elements to change value. For example, if I code:
9 choose big_array 128 + c!
then the array will become:
0 4 0 4 2 6 0 5 2 5 7 3
6 3 7 3 7 7 3 1 5 0 6 1
0 3 3 0 3 1 0 7 2 0 4 5
3 7 6 6 2 1 0 2 3 4 2 7
4 7 1 5 3 5 7 2 3 5 3 6
3 0 6 4 1 3 3 2 5 4 4 7
3 2 1 4 3 4 3 7 2 6 5 5
2 4 4 3 4 5 4 4 6 5 6 0
2 5 2 7 3 1 5 0 1 4 6 7
2 0 3 3 0 7 3 6 4 1 3 6
0 1 1 6 0 3 0 2 2 12 194 69
7 2 3 1 2 2 7 6 0 5 1 2
Do you have any idea why these specific elements are always impacted and if there is a way to prevent this?
Better readability and less error prone: 144 allocate ⇨ 144 chars allocate
A mistake: create big_array 144 allocate drop ⇨ create big_array 144 chars allot
A mistake: random um* nip ⇨ random swap mod
A mistake: 144 1 do ⇨ 144 0 do
An excessive operation: big_array swap + ⇨ big_array +
And add the stack comments, please. Especially, when you ask for help.
Do you have any idea why these specific elements are always impacted and if there is a way to prevent this?
Since you try to use memory in the dictionary space without reserving it. This memory is used by the Forth system.

How to remove extra duplicated elements in each row of a matrix in matlab?

Let's say I have a matrix
A = [2 3 2 5 6 7 2;
1 2 5 4 5 6 7;
7 5 3 9 8 1 2];
How do I remove 2s and keep one 2 in the first row and keep only one 5 in the second row?
The result can't be a matrix anymore, because each row will have a different length. You can obtain the result as a cell array of row vectors as follows:
B = mat2cell(A, ones(size(A,1),1)); %// convert matrix to cell array of its rows
B = cellfun(#(x) unique(x,'stable'), B, 'uniformoutput', 0); %// stably remove duplicates
For your example matrix
A = [2 3 2 5 6 7 2;
1 2 5 4 5 6 7;
7 5 3 9 8 1 2];
this gives
B{1} =
2 3 5 6 7
B{2} =
1 2 5 4 6 7
B{3} =
7 5 3 9 8 1 2
If you want to find out which values are duplicates within the row, you can do something like this:
[vals, col_idx] = sort(A,2);
idx = bsxfun(#plus,(col_idx-1)*size(A,1), (1:size(A,1))');
is_duplicate(idx(:,2:end)) = vals(:,1:end-1) == vals(:,2:end);
is_duplicate = reshape(is_duplicate, size(A));
is_duplicate =
0 0 1 0 0 0 1
0 0 0 0 1 0 0
0 0 0 0 0 0 0
From there, it depends what outcome you are looking for. You could set the duplicates to NaN or some other value, or you could set them to NaN, but then shift them to the end of the row, using something like the following:
col_idx = cumsum(~is_duplicate, 2);
idx = bsxfun(#plus,(col_idx-1)*size(A,1), (1:size(A,1))');
A_new = nan(size(A));
A_new(idx(~is_duplicate)) = A(~is_duplicate);
A_new =
2 3 5 6 7 NaN NaN
1 2 5 4 6 7 NaN
7 5 3 9 8 1 2

Sum row vectors IF two or more rows in given column match (MATLAB)

I have a 48x202 matrix, where the first columns in the matix is an ID, and the rest of the columns is related vectors to the row ID in the first column.
The ID column is sorted in acending order, and multiple rows can have the same ID.
I want to summarize all IDs that are equal, meaning that i want to sum the rows in the matrix who has identical ID in the first column.
The resulting matrix should be 32x202, since there are only 32 IDs.
Any ideas?
I'd totally approach this with accumarray as well as unique. Like the previous answer, let A be your matrix. You would obtain your answer thusly:
[vals,~,id] = unique(A(:,1),'stable');
B = accumarray(id, (1:numel(id)).', [], #(x) {sum(A(x,2:end),1)});
out = [vals cell2mat(B)];
The first line of code produces vals which is a list of all unique IDs seen in the first column of A and id assigns a unique integer ID without any gaps from 1 up to as many unique IDs there are in the first column of A. The reason why you want to do this is for the next line of code.
How accumarray works is that you provide a set of keys and a set of values associated with each key. accumarray groups all values that belong to the same key and does something to all of the values. The keys in our case is the IDs given in the first column of A and the values are the actual row locations of the matrix A from 1 up to as many rows as A. Now, the default behaviour when collecting all of the values together is to sum all of the values that belong to the same key together, but we're going to do something a bit different. What we'll do is that for each unique ID seen in the first column of A, there will be a bunch of row locations that map to the same ID. We're going to use these row locations and will access the matrix A and sum all of the columns from the second column to the end. That's what the anonymous function in the fourth argument of accumarray is doing. accumarray traditionally should output a single value representing all of the values mapped to a key, but we get around this by outputting a single cell, where each cell entry is the row sum of the mapped columns.
Each element of B gives you the row sum for each corresponding unique value in vals and so the last line of code pieces these together - the unique value in vals with the corresponding row sum. I had to use cell2mat because this was a matrix of cells and I had to convert all of these into a numerical matrix to complete the task.
Here's an example seeing this in action. I'm going to do this for a smaller set of data:
>> rng(123);
>> A = [[1;1;1;2;2;2;2;3;3;4;4;5;6;7] randi(10, 14, 10)];
>> A
A =
1 7 4 3 4 5 1 10 3 2 3
1 3 8 7 5 7 9 9 4 9 6
1 3 2 1 9 9 7 4 6 4 9
2 6 2 5 3 6 8 1 7 6 4
2 8 6 5 5 7 1 4 2 6 8
2 5 6 5 10 6 6 4 2 6 2
2 10 7 5 6 7 6 8 4 1 7
3 7 9 4 7 7 2 10 7 10 9
3 5 8 5 2 9 2 4 9 10 10
4 4 7 9 9 1 7 8 6 3 1
4 4 8 10 7 8 4 6 9 3 5
5 8 4 6 6 3 7 7 4 6 3
6 5 4 7 4 2 6 2 4 10 5
7 1 3 2 4 6 4 4 4 10 6
The first column is our IDs, and the next columns are the data. Running the above code I just wrote, we get:
>> out
out =
1 13 14 11 18 21 17 23 13 15 18
2 29 21 20 24 26 21 17 15 19 21
3 12 17 9 9 16 4 14 16 20 19
4 8 15 19 16 9 11 14 15 6 6
5 8 4 6 6 3 7 7 4 6 3
6 5 4 7 4 2 6 2 4 10 5
7 1 3 2 4 6 4 4 4 10 6
If you double check each row, summing over all of the columns that match each of the column IDs matches up. For example, the first three rows map to the same ID, and we should sum up all of these rows and we get the corresponding sum. The second column is equal to 7+3+3=13, the third column is equal to 4+8+2=14, etc.
Another approach is to apply unique and then use bsxfun to build a matrix that multiplied by the non-ID part of the input matrix will give the result.
Let the input matrix be denoted as A. Then:
[u, ~, v] = unique(A(:,1));
result = [ u bsxfun(#eq, u, u(v).') * A(:,2:end) ];
Example: borrowing from #rayryeng's answer, let
A = [ 1 7 4 3 4 5 1 10 3 2 3
1 3 8 7 5 7 9 9 4 9 6
1 3 2 1 9 9 7 4 6 4 9
2 6 2 5 3 6 8 1 7 6 4
2 8 6 5 5 7 1 4 2 6 8
2 5 6 5 10 6 6 4 2 6 2
2 10 7 5 6 7 6 8 4 1 7
3 7 9 4 7 7 2 10 7 10 9
3 5 8 5 2 9 2 4 9 10 10
4 4 7 9 9 1 7 8 6 3 1
4 4 8 10 7 8 4 6 9 3 5
5 8 4 6 6 3 7 7 4 6 3
6 5 4 7 4 2 6 2 4 10 5
7 1 3 2 4 6 4 4 4 10 6 ];
Then the result is
result =
1 13 14 11 18 21 17 23 13 15 18
2 29 21 20 24 26 21 17 15 19 21
3 12 17 9 9 16 4 14 16 20 19
4 8 15 19 16 9 11 14 15 6 6
5 8 4 6 6 3 7 7 4 6 3
6 5 4 7 4 2 6 2 4 10 5
7 1 3 2 4 6 4 4 4 10 6
and the intermediate matrix created with bsxfun is
>> bsxfun(#eq, u, u(v).')
ans =
1 1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1
Pre-multiplying A by this matrix means that the first three rows of A are added to give the first row of the result; then the following four rows of A are added to give the second row of the result, etc.
You can find the unique row IDs with unique and then loop over all of those, summing the other columns: Let A be your matrix, then
rID = unique(A(:, 1));
B = zeros(numel(rID), size(A, 2));
for ii = 1:numel(rID)
B(ii, 1) = rID(ii);
B(ii, 2:end) = sum(A(A(:, 1) == rID(ii), 2:end), 1);
end
B contains your output.

Keep n largest values per column and set the rest to zero in MATLAB without a loop

I have a matrix of unsorted numbers and I want to keep the n largest (not necessarily unique) values per column and set the rest to zero.
I figured out how to do it with a loop:
a = [4 8 12 5; 9 2 6 18; 11 3 9 7; 8 9 12 4]
k = 2
for n = 1:4
[y, ind] = sort(a(:,n), 'descend');
a(ind(k+1:end),n) = 0;
end
a
which gives me:
a =
4 8 12 5
9 2 6 18
11 3 9 7
8 9 12 4
k =
2
a =
0 8 12 0
9 0 0 18
11 0 0 7
0 9 12 0
However when I try to eliminate the loop, I can't seem to get the indexing right, because this:
a = [4 8 12 5; 9 2 6 18; 11 3 9 7; 8 9 12 4]
k = 2
[y, ind] = sort(a, 'descend');
b = ind(k+1:end,:)
a(b) = 0
which gives me this: (which is not what I wanted to do)
a =
4 8 12 5
9 2 6 18
11 3 9 7
8 9 12 4
k =
2
b =
4 3 3 1
1 2 2 4
a =
0 8 12 5
0 2 6 18
0 3 9 7
0 9 12 4
Am I indexing this wrong? Do I have to use the loop?
I referenced this question to get started but it wasn't exactly what I was trying to do: How to find n largest elements in an array and make the other elements zero in matlab?
You're very close. ind in the sort function gives you the row locations for each column where that particular value would appear in the sorted output. You need to do some additional work if you want to index into the matrix properly and eliminate the entries. You know that for each column of I, that tells you that we need to eliminate those entries from that particular column. Therefore, what I would do is generate column-major linear indices using each column of I to be the rows we need to eliminate.
Try doing this:
a = [4 8 12 5; 9 2 6 18; 11 3 9 7; 8 9 12 4];
k = 2;
[y, ind] = sort(a, 'descend');
%// Change here
b = sub2ind(size(a), ind(k+1:end,:), repmat(1:size(a,2), size(a,1)-k, 1));
a(b) = 0;
We use sub2ind to help us generate our column major indices where the rows are denoted by the values in ind after the kth element and the columns we need are for each column in this matrix. There are size(a,1)-k rows remaining after you truncate out the k values after sorting, and so we generate column values that go from 1 up to as many columns as we have in a and as many rows as there are remaining.
We get this output:
>> a
a =
0 8 12 0
9 0 0 18
11 0 0 7
0 9 12 0
Here's one using bsxfun -
%// Get descending sorting indices per column
[~, ind] = sort(a,1, 'descend')
%// Get linear indices that are to be set to zeros and set those in a to 0s
rem_ind = bsxfun(#plus,ind(n+1:end,:),[0:size(a,2)-1]*size(a,1))
a(rem_ind) = 0
Sample run -
a =
4 8 12 5
9 2 6 18
11 3 9 7
8 9 12 4
n =
2
ind =
3 4 1 2
2 1 4 3
4 3 3 1
1 2 2 4
rem_ind =
4 7 11 13
1 6 10 16
a =
0 8 12 0
9 0 0 18
11 0 0 7
0 9 12 0

how to vectorize the following for loop?

can any one help me to Vectorized this loop.
i have large Matrix and i want to replace all the pixel values whose length is less then some threshold Value For simplicity lets say
a = randi([1 5],10,10);
for i = 1:length(a)
someMat=a(a==i);
if length(someMat)<20
a(a==i)=0;
end
end
but its killing me.
Example:
a = randi([1 5],10,10)
a =
5 2 1 5 5 5 2 2 3 2
3 3 5 4 4 4 3 1 1 5
5 1 3 5 3 3 4 1 3 1
3 1 5 3 2 5 1 1 5 1
1 1 4 3 4 3 4 4 5 1
1 4 3 5 1 1 2 2 2 1
3 3 5 2 4 1 1 3 2 4
4 1 5 3 4 5 3 4 3 3
5 3 5 5 4 3 1 3 4 1
4 1 1 3 5 5 1 3 3 5
Result for Thresold 20
5 0 1 5 5 5 0 0 3 0
3 3 5 0 0 0 3 1 1 5
5 1 3 5 3 3 0 1 3 1
3 1 5 3 0 5 1 1 5 1
1 1 0 3 0 3 0 0 5 1
1 0 3 5 1 1 0 0 0 1
3 3 5 0 0 1 1 3 0 0
0 1 5 3 0 5 3 0 3 3
5 3 5 5 0 3 1 3 0 1
0 1 1 3 5 5 1 3 3 5
length of pixel 4 was 17
length of pixel 2 was 10
i try it by some thing like
[nVal Index] = histc(a(:),unique(a)); %
nVal(nVal>20) = 1; % just some threshold value and assigning by some Number may be zero as well
But I dont Know how to replace the Index Values of the corresponding Pixal and apply reshape to get it in original form. Here Even i am not sure that i will get the same Matrix With Reshape . Please Help me.....
thanks
I think this does what you want:
threshold_length = 20;
replace_value = 0;
u = unique(a); %// values of a
h = histc(a(:), u); %// count for each value
r = u(h<threshold_length); %// values to be removed
a(ismember(a,r)) = replace_value; %// remove those values
I see #LuisMendo arrived at mostly the same solution quicker than I did, but an alternative to using ismember is to use more of what unique gives you:
threshold = 20;
[vals, ~, ix] = unique(a); % capture the values and their indices
counts = histc(a(:), vals); % count the occurrences of each value
vals(counts<threshold) = 0; % zero the values that aren't common enough
a(:) = vals(ix); % recreate the matrix with updated values

Resources