How to create a Boolean Numpy Array using fancy indexing - arrays

I have the following dummy array:
>>> arr
[[0 0 1 0 0 1 0 1 1 1 0 0]
[1 1 0 1 1 0 0 0 0 0 1 1]
[1 1 0 1 0 1 0 0 0 0 1 0]
[1 1 0 1 1 0 1 1 0 0 0 1]
[0 1 0 1 0 1 1 1 0 0 0 1]
[1 0 1 1 1 0 0 1 0 0 1 1]]
I also have some "mutations" I would like to incorporate into my array, at the following positions (note these are generated randomly each time, so I cannot just set them manually):
row = [0 4 3]
col = [11 10 7]
I know I can target each (row, col) pair using fancy indexing with arr[row, col] = -3 (for example, set those elements to -3).
However, what I want to do is a bitwise NOT - aka something like this:
arr[row, col] = ~arr
I tried using np.where(), but it won't accept arr[row, col] b/c it doesn't generate a boolean array.
Any suggestions? How can I create a boolean array to use as a where conditional
(also yes, I know I can make an array of all zeros in the same shape as arr and then set those positions to 1's and use that as a mask - I'd love something cleaner tho)
Thanks!

Related

How to balance unique values in an array Matlab

I have a vector
Y = [1 1 0 0 0 1 1 0 1 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 0 0]
1 occurs 17 times
0 occurs 21 times
How can I randomly remove 0s so that both values have equal amounts, such as 1 (17 times) and 0 (17 times)?
This should also work on much bigger matrix.
Starting with your example
Y = [1 1 0 0 0 1 1 0 1 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 0 0]
You can do the following:
% Get the indices of the value which is more common (`0` here)
zeroIdx = find(~Y); % equivalent to find(Y==0)
% Get random indices to remove
remIdx = randperm(nnz(~Y), nnz(~Y) - nnz(Y));
% Remove elements
Y(zeroIdx(remIdx)) = [];
You could combine the last two lines, but I think it would be less clear.
The randperm line is choosing the correct number of elements to remove from random indices between 1 and the number of zeros.
If the data can only have two values
Values are assumed to be 0 and 1. The most common value is randomly removed to equalize their counts:
Y = [1 1 0 0 0 1 1 0 1 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 0 0]; % data
ind0 = find(Y==0); % indices of zeros
ind1 = find(Y==1); % indices of ones
t(1,1:numel(ind0)) = ind0(randperm(numel(ind0))); % random permutation of indices of zeros
t(2,1:numel(ind1)) = ind1(randperm(numel(ind1))); % same for ones. Pads shorter row with 0
t = t(:, all(t,1)); % keep only columns that don't have padding
result = Y(sort(t(:))); % linearize, sort and use those indices into the data
Generalization for more than two values
Values are arbitrary. All values except the least common one are randomly removed to equalize their counts:
Y = [0 1 2 0 2 1 1 2 0 2 1 2 2 0 0]; % data
vals = [0 1 2]; % or use vals = unique(Y), but absent values will not be detected
t = [];
for k = 1:numel(vals) % loop over values
ind_k = find(Y==vals(k));
t(k, 1:numel(ind_k)) = ind_k(randperm(numel(ind_k)));
end
t = t(:, all(t,1));
result = Y(sort(t(:)));

How to copy and paste a small matrix into a bigger matrix without for-loop

For example, we have a small matrix
B = [5 2,
3 4]
and the bigger one
A = [1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1]
Now I want paste B into A so that A looks like
A = [1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 5 2
0 0 0 3 4]
That means the values of A of the bottom right has been replaced. I would like to do this without using a for-loop. How is that possible?
PS:
A is always an eye(n) matrix (n is a constant).
B is a square matrix and has a variable size but is always less or equal to A
Find the relevant row and column subscripts of A and put B there.
A(end-size(B,1)+1:end, end-size(B,2)+1:end)=B
It works even if B is not a square matrix.

Counting values along an axis in a 3D array that are greater than threshold values from a 2D array

I have a 3D array of dimensions (200,200,3). These are images of dimensions (200,200) stacked using numpy.dstack. I would like to count the number of values along axis=2 that are greater than a corresponding 2D threshold array of dimensions (200,200). The output counts array should have dimensions (200,200). Here is my code so far.
import numpy as np
stacked_images=np.random.rand(200,200,3)
threshold=np.random.rand(200,200)
counts=(stacked_images<threshold).sum(axis=2)
I am getting the following error.
ValueError: operands could not be broadcast together with shapes (200,200,3) (200,200)
The code works if threshold is an integer/float value. For example.
threshold=0.3
counts=(stacked_images<threshold).sum(axis=2)
Is there a simple way to do this if threshold is a 2D array? I guess I am not understanding numpy broadcasting rules correctly.
numpy is expecting to make a value by value operation. In your case you seem to be wanting to know if any value in the full Z (axis=2) trace exceeds the equivalent x, y value in threshold.
As so just make sure threshold has the same shape, namely by building a 3D threshold using whatever method you prefer. Since you mentioned numpy.dstack:
import numpy as np
stacked_images = np.random.rand(10, 10, 3)
t = np.random.rand(10, 10)
threshold = np.dstack([t, t, t])
counts = (stacked_images < threshold).sum(axis=2)
print(counts)
, which results in:
[[2 0 3 3 1 3 1 0 1 2]
[0 1 2 0 0 1 0 0 1 3]
[2 1 3 0 3 2 1 3 1 3]
[2 0 0 3 3 2 0 2 0 1]
[1 3 0 0 0 3 0 2 1 2]
[1 1 3 2 3 0 0 3 0 3]
[3 1 0 1 2 0 3 0 0 0]
[3 1 2 1 3 0 3 2 0 2]
[3 1 1 2 0 0 1 0 1 0]
[0 2 2 0 3 0 0 2 3 1]]

Concatenate binary strings obtained from decimal to binary conversion

I want to place the binary equivalent number for each element side - by side i.e, the final matrix Concatenated_A would be of size m by nbits*n where [m,n] = size(A);
A = [5, 5, 4, 10, 4;
10, 10, 10, 10, 5;
];
I did an attempt but the result is wrong. I need help in correctly implementing the concatenation. Thank you
[m,n] = size(A);
numbits = 4;
for m = 1:M
Abin = dec2bin(A(m,:),numbits);
for j = 1:size(Abin,1)
Concatenated_A(m,:) = Abin(j,:);
end
end
For first row in A(1,:) = 5, 5, 4, 10, 4 ; its decimal conversion of each element would give a matrix as below.
0 1 0 1
0 1 0 1
0 1 0 0
1 0 1 0
0 1 0 0
Then, how can I do something like this :
Concatenated_A(1,:) = [0 1 0 1 0 1 0 1 0 1 0 0 1 0 1 0 0 1 0 0]
The above operation is repeated for every row in A.
You can transpose the result of dec2bin so that the binary representation goes down the columns and then reshape this into the desired shape so that each row is on it's own row. After reshaping, we take the transpose again so that the rows go across the rows again. Also we need to be sure to transpose A before we start so that we encode along the rows.
out = reshape(dec2bin(A.', numbits).', [], size(A, 1)).'
% 01010101010010100100
% 10101010101010100101
Or if you want a logical matrix instead you can compare your character array to the character '1'
out = reshape(dec2bin(A.', numbits).', [], size(A, 1)).' == '1'
% 0 1 0 1 0 1 0 1 0 1 0 0 1 0 1 0 0 1 0 0
% 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 0 1 0 1

How to change elements of a matrix with reference to a vector of column indices without using for-loop?

I have a matrix
a =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
and b vector
b =
1 2 3 4 5 5
I want to replace value of each row in a matrix with reference value of b matrix value and finally generate a matrix as follows without using for loop.
a_new =
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
0 0 0 0 1
if first element of b, b(1) = 1 so change take first row of a vector and make first element as 1 because b(1) = 1.
How can I implement this without using for loop?
Sure. You only need to build a linear index from b and use it to fill the values in a:
a = zeros(6,5); % original matrix
b = [1 2 3 4 5 5]; % row or column vector with column indices into a
ind = (1:size(a,1)) + (b(:).'-1)*size(a,1); % build linear index
a(ind) = 1; % fill value at those positions
Same as Luis Mendo's answer, but using the dedicated function sub2ind:
a( sub2ind(size(a),(1:numel(b)).',b(:)) ) = 1
Also via the subscript to indices conversion way,
a = zeros(6,5);
b = [1 2 3 4 5 5];
idx = sub2ind(size(a), [1:6], b); % 1:6 just to create the row index per b entry
a(idx) = 1
any of these methods works in Octave:
bsxfun(#eq, [1:5 5]',(1:5))
[1:5 5].' == (1:5)

Resources