"Trailing" One-Hot Encode - python

I am trying to do something similar to One-Hot-Encoding but instead of the selected class being 1 and the rest zero, I want all the classes up to (and including the selected class) to be 1. Say I have a training batch with labels (5 possible class labels; 0, 1, 2, 3, 4)
y = np.array([0,2,1,3,4,1])
I can one-hot-encode with
def one_hot_encode(arr, num_classes):
return np.eye(num_classes)[arr]
which gives
>>> one_hot_encode(y, 5)
array([[ 1., 0., 0., 0., 0.],
[ 0., 0., 1., 0., 0.],
[ 0., 1., 0., 0., 0.],
[ 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 1.],
[ 0., 1., 0., 0., 0.]])
I liked to get
array([[ 1., 0., 0., 0., 0.],
[ 1., 1., 1., 0., 0.],
[ 1., 1., 0., 0., 0.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 0., 0., 0.]])
Anyone know how to do this?

You could achieve this by using a lower-triangular matrix instead of an identity matrix in your function definition:
def many_hot_encode(arr, num_classes):
return np.tril(np.ones(num_classes))[arr]
many_hot_encode(y,5)
array([[ 1., 0., 0., 0., 0.],
[ 1., 1., 1., 0., 0.],
[ 1., 1., 0., 0., 0.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 0., 0., 0.]])

You can also use broadcasting -
out = (y[:,None] >= np.arange(num_classes)).astype(float)
Sample run -
In [71]: y = np.array([0,2,1,3,4,1])
In [72]: num_classes = 5
In [73]: (y[:,None] >= np.arange(num_classes)).astype(float)
Out[73]:
array([[ 1., 0., 0., 0., 0.],
[ 1., 1., 1., 0., 0.],
[ 1., 1., 0., 0., 0.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 0., 0., 0.]])

Related

Adding zeros in between elements in numpy array with (a,b,c) shape

I have a numpy array like this
array([[[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]],
[[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]]])
shape = (2, 3, 5)
And I want an output which looks like this
output = array([[[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.],
[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.],
[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.]],
[[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.],
[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.],
[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.]]])
Note: The number of zeros to be inserted can vary depending on given factor, in this case the factor was k=3, and the insert is (k-1) which means two zeros will be inserted between numbers. Also given this output I would like to get to the initial input
You can use numpy.zeros to initialize an output array of the desired shape, then indexing to fill the values:
k = 3
shape = a.shape
output = np.zeros(shape[:-1]+((shape[-1]-1)*k+1,))
output[...,::k] = a
output:
array([[[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.],
[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.],
[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.]],
[[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.],
[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.],
[1., 0., 0., 1., 0., 0., 1., 0., 0., 1., 0., 0., 1.]]])

Python: How do I generate a random matrix of 1.0 and 0.0, but with floats?

I am currently coding Conway's game of life and to add randomization to my world I have implemented a function to create a random matrix with 1 and 0 with n rows and n columns.
The problem is that, for my code to work, I need a random matrix of 1 and 0 but they have to be floats, so 0.0 and 1.0
So I cannot use:
rand_matrix = numpy.random.randint(0, 2, size=n)
Instead I have tried:
n = 10
one_zero = [0.0,1.0]
rand_matrix = np.array([n*[random.choice(one_zero),random.choice(one_zero)],n*[random.choice(one_zero),random.choice(one_zero)]])
Getting:
[[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1. 0. 1.]]
But this returns a matrix of different dimensions, what I want is a random n by n matrix. And each row should be a combination of 0.0 and 1.0 randomly chosen.
>>> np.random.randint(0, 2, (10, 10)).astype(float)
array([[0., 0., 0., 1., 1., 0., 1., 1., 1., 1.],
[1., 1., 1., 1., 0., 1., 1., 0., 0., 1.],
[1., 0., 1., 0., 1., 1., 1., 1., 0., 0.],
[1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 1., 1., 1., 0., 1., 0., 1.],
[0., 1., 1., 1., 0., 0., 1., 0., 0., 0.],
[0., 1., 1., 0., 1., 0., 0., 1., 1., 0.],
[0., 0., 0., 1., 0., 0., 1., 0., 1., 0.],
[0., 1., 1., 1., 1., 1., 1., 0., 1., 1.],
[0., 1., 0., 1., 1., 1., 0., 0., 0., 0.]])
You can just cast the randint() matrix to float:
>>> import numpy as np
>>> n = 10
>>> rand_matrix = np.random.randint(0, 2, size=(n, n)).astype(float)
array([[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
[0., 0., 0., 1., 1., 1., 0., 0., 1., 1.],
[1., 1., 1., 1., 0., 0., 1., 1., 0., 0.],
[1., 0., 0., 1., 0., 1., 0., 1., 0., 1.],
[0., 0., 0., 0., 1., 1., 0., 1., 1., 1.],
[0., 1., 1., 1., 1., 0., 1., 1., 1., 0.],
[0., 0., 1., 0., 0., 0., 0., 1., 0., 1.],
[1., 0., 0., 1., 0., 0., 1., 1., 1., 0.],
[1., 0., 0., 0., 0., 0., 1., 1., 1., 1.],
[1., 0., 0., 1., 1., 1., 1., 1., 1., 0.]])
>>>

How do I convert int8 into its binary representation in pytorch?

Given a pytorch tensor in dtype=int8:
tensor([[[-3, -6, -1],
[-6, -10, -1,
[9, 9, 6],
[[-4, -7, -3],
[-4, -6, -1],
[14, 16, 8]],
[[-4, -6, -2],
[-6, -9, -2],
[9, 10, 5]]], device='cuda:0', dtype=torch.int8)
How do I convert the above tensor into its binary representation?
I tried to convert to numpy to use np.unpackbits function but it only takes un-sign integer 8 as input.
Change the dtype from torch.int8 to torch.uint8.
This is the required output that I want:
tensor([[[[1., 1., 1., 1., 1., 1., 0., 1.],
[1., 1., 1., 1., 1., 0., 1., 0.],
[1., 1., 1., 1., 1., 1., 1., 1.]],
[[1., 1., 1., 1., 1., 0., 1., 0.],
[1., 1., 1., 1., 0., 1., 1., 0.],
[1., 1., 1., 1., 1., 1., 1., 1.]],
[[0., 0., 0., 0., 1., 0., 0., 1.],
[0., 0., 0., 0., 1., 0., 0., 1.],
[0., 0., 0., 0., 0., 1., 1., 0.]]],
[[[1., 1., 1., 1., 1., 1., 0., 0.],
[1., 1., 1., 1., 1., 0., 0., 1.],
[1., 1., 1., 1., 1., 1., 0., 1.]],
[[1., 1., 1., 1., 1., 1., 0., 0.],
[1., 1., 1., 1., 1., 0., 1., 0.],
[1., 1., 1., 1., 1., 1., 1., 1.]],
[[0., 0., 0., 0., 1., 1., 1., 0.],
[0., 0., 0., 1., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0., 0., 0.]]],
[[[1., 1., 1., 1., 1., 1., 0., 0.],
[1., 1., 1., 1., 1., 0., 1., 0.],
[1., 1., 1., 1., 1., 1., 1., 0.]],
[[1., 1., 1., 1., 1., 0., 1., 0.],
[1., 1., 1., 1., 0., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 0., 0.]],
[[0., 0., 0., 0., 1., 0., 0., 1.],
[0., 0., 0., 0., 1., 0., 1., 0.],
[0., 0., 0., 0., 0., 1., 0., 1.]]]], device='cuda:0',
grad_fn=<RemainderBackward0>)
I found a helpful repo that has a function which converts int8 into binary like above
https://github.com/KarenUllrich/pytorch-binary-converter.git
Adapted from my answer for Convert integer to pytorch tensor of binary bits, here's something more concise than the repo from your answer:
a = torch.tensor([[[-3, -6, -1],
[-6, -10, -1],
[ 9, 9, 6]],
[[-4, -7, -3],
[-4, -6, -1],
[14, 16, 8]],
[[-4, -6, -2],
[-6, -9, -2],
[ 9, 10, 5]]], dtype=torch.int8)
def int_to_bits(x, bits=None, dtype=torch.uint8):
assert not(x.is_floating_point() or x.is_complex()), "x isn't an integer type"
if bits is None: bits = x.element_size() * 8
mask = 2**torch.arange(bits-1,-1,-1).to(x.device, x.dtype)
return x.unsqueeze(-1).bitwise_and(mask).ne(0).to(dtype=dtype)
int_to_bits(a, dtype=torch.float32)
This returns:
tensor([[[[1., 1., 1., 1., 1., 1., 0., 1.],
[1., 1., 1., 1., 1., 0., 1., 0.],
[1., 1., 1., 1., 1., 1., 1., 1.]],
[[1., 1., 1., 1., 1., 0., 1., 0.],
[1., 1., 1., 1., 0., 1., 1., 0.],
[1., 1., 1., 1., 1., 1., 1., 1.]],
[[0., 0., 0., 0., 1., 0., 0., 1.],
[0., 0., 0., 0., 1., 0., 0., 1.],
[0., 0., 0., 0., 0., 1., 1., 0.]]],
[[[1., 1., 1., 1., 1., 1., 0., 0.],
[1., 1., 1., 1., 1., 0., 0., 1.],
[1., 1., 1., 1., 1., 1., 0., 1.]],
[[1., 1., 1., 1., 1., 1., 0., 0.],
[1., 1., 1., 1., 1., 0., 1., 0.],
[1., 1., 1., 1., 1., 1., 1., 1.]],
[[0., 0., 0., 0., 1., 1., 1., 0.],
[0., 0., 0., 1., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0., 0., 0.]]],
[[[1., 1., 1., 1., 1., 1., 0., 0.],
[1., 1., 1., 1., 1., 0., 1., 0.],
[1., 1., 1., 1., 1., 1., 1., 0.]],
[[1., 1., 1., 1., 1., 0., 1., 0.],
[1., 1., 1., 1., 0., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 0.]],
[[0., 0., 0., 0., 1., 0., 0., 1.],
[0., 0., 0., 0., 1., 0., 1., 0.],
[0., 0., 0., 0., 0., 1., 0., 1.]]]])

Is there a numpy way to reduce arrays?

I have this numpy array which is a concatention of other numpy arrays
array([array([[ 0., 1., 0., 0., 1., 0.]]),
array([[ 1., 0., 0., 1., 0., 0.]]),
array([[ 0., 0., 0., 0., 1., 1.]]),
array([[ 0., 1., 0., 0., 0., 1.]]),
array([[ 0., 1., 0., 1., 0., 0.]]),
array([[ 1., 0., 0., 0., 0., 1.]])], dtype=object)
its current shape is (6,). what I want is this with a shape (6,6)
array([[ 0., 1., 0., 0., 1., 0.],
[ 1., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 1., 1.],
[ 0., 1., 0., 0., 0., 1.],
[ 0., 1., 0., 1., 0., 0.],
[ 1., 0., 0., 0., 0., 1.]], dtype=object)
Is there a numpy way to solve this problem or do I have to loop through the arrays and append it?
If the display is accurate, and the array really is (6,), then we have to recreate it with:
In [27]: array=np.array
In [28]: alist = [array([[ 0., 1., 0., 0., 1., 0.]]),
...: array([[ 1., 0., 0., 1., 0., 0.]]),
...: array([[ 0., 0., 0., 0., 1., 1.]]),
...: array([[ 0., 1., 0., 0., 0., 1.]]),
...: array([[ 0., 1., 0., 1., 0., 0.]]),
...: array([[ 1., 0., 0., 0., 0., 1.]])]
...:
In [29]: A = np.empty((6,),object)
In [30]: A
Out[30]: array([None, None, None, None, None, None], dtype=object)
In [31]: A[:]=alist
In [32]: A
Out[32]:
array([array([[ 0., 1., 0., 0., 1., 0.]]),
array([[ 1., 0., 0., 1., 0., 0.]]),
array([[ 0., 0., 0., 0., 1., 1.]]),
array([[ 0., 1., 0., 0., 0., 1.]]),
array([[ 0., 1., 0., 1., 0., 0.]]),
array([[ 1., 0., 0., 0., 0., 1.]])], dtype=object)
reshape does not work:
In [33]: A.reshape(6,6)
...
ValueError: cannot reshape array of size 6 into shape (6,6)
But the array can be treated as a list, and given to concatenate:
In [34]: np.concatenate(A, axis=1)
Out[34]:
array([[ 0., 1., 0., 0., 1., 0., 1., 0., 0., 1., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0., 1., 0., 1.,
0., 1., 0., 0., 1., 0., 0., 0., 0., 1.]])
In [35]: np.concatenate(A, axis=0)
Out[35]:
array([[ 0., 1., 0., 0., 1., 0.],
[ 1., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 1., 1.],
[ 0., 1., 0., 0., 0., 1.],
[ 0., 1., 0., 1., 0., 0.],
[ 1., 0., 0., 0., 0., 1.]])
Concatenate on the list works just as well: np.concatenate(alist, axis=0)
I should note that the resulting array is dtype float, not object. It could be converted with astype, but who would want that?
Simple copy-n-paste produces a 3d array, since the outer array ignores the inner division and creates as high-a-dimensional array as it can:
In [37]: array([array([[ 0., 1., 0., 0., 1., 0.]]),
...: array([[ 1., 0., 0., 1., 0., 0.]]),
...: array([[ 0., 0., 0., 0., 1., 1.]]),
...: array([[ 0., 1., 0., 0., 0., 1.]]),
...: array([[ 0., 1., 0., 1., 0., 0.]]),
...: array([[ 1., 0., 0., 0., 0., 1.]])])
Out[37]:
array([[[ 0., 1., 0., 0., 1., 0.]],
[[ 1., 0., 0., 1., 0., 0.]],
...
[[ 1., 0., 0., 0., 0., 1.]]])
In [38]: _.shape
Out[38]: (6, 1, 6)
So we need to careful how we recreate cases like this.
You should try this:
my_array = my_array.reshape(6,6)
It works with the above array when pasted as is as it will remove the third dimension. Other methods like vstack and concatenate as shown on #Divikar comment above should work as well for this purpose

reduce() hstack python

I am trying to use reduce() function to create a function hstack() which horizontally stacks multiple arrays. As a simple example, lets say
>>>>M=eye((4))
>>>>M
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])
>>>>hstack([M,M])
array([[ 1., 0., 0., 0., 1., 0., 0., 0.],
[ 0., 1., 0., 0., 0., 1., 0., 0.],
[ 0., 0., 1., 0., 0., 0., 1., 0.],
[ 0., 0., 0., 1., 0., 0., 0., 1.]])
This works as I want. Now I define
>>>> hstackm = lambda *args: reduce(hstack, args)
And try to do the hstack() from the previous case
>>>>hstackm([M,M])
[array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]]),
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])]
Which is incorrect. How do I define hstackm() to obtain a proper output?
My final objective will be to create a hstackm() function to stack SPARSE matrices if it is possible. Something like,
hstackm = lambda *args: reduce(sparse.hstack, args).
The _*args_ would be csr or _lil_matrix_
thank you
In [16]: hstackm = lambda args: reduce(lambda x,y:hstack((x,y)), args)
In [17]: hstackm([M,M])
Out[17]:
array([[ 1., 0., 0., 0., 1., 0., 0., 0.],
[ 0., 1., 0., 0., 0., 1., 0., 0.],
[ 0., 0., 1., 0., 0., 0., 1., 0.],
[ 0., 0., 0., 1., 0., 0., 0., 1.]])
Your function hstack takes one parameter, a list of matrices. reduce() calls it with two parameters instead, each a matrix.
Change your hstack method to accept an arbitrary number of arguments instead:
def hstack(*matrices):
....
instead of hstack(matrices), then call it as hstack(M, M).

Categories

Resources