How to build a vector of marginal probabilities, given a tensor in PyTorch
How to build a vector of marginal probabilities, given a tensor in PyTorch
I have a tensor 'A' of shape [ Dim1: &lt;128&gt;, Dim2: &lt;64&gt;], each element in Dim1 is drawn from a unknown distribution and I need to check if the Dim2 vector has appeared before in the other 128 samples. If it has, the marginal probability of this element is increased by 1 and recorded in another tensor 'B' which is of shape [DimB: &lt;128&gt;]. When the iteration is complete I divide all elements in B by 128 (the number of possibilities) to achieve the weighted delta, therefore the aim is to approximate the true distribution as Dim1 increases in size.
How can this be achieved directly in PyTorch? I attempted it with ordered dictionaries but it's too slow. I'm assuming a method exists to do it straight in PyTorch
my crude way to do it with ordered dictionaries if we have a tensor T1 of shape [Dim1: &lt;6&gt;, Dim2: &lt;3&gt;]:
from collections import OrderedDict
od = OrderedDict()
T1 = torch.Tensor([[2.4, 5.5,1],
                   [3.44,5.43,1],
                   [2.4, 5.5,1],
                   [3.44,8.43,1],
                   [3.44,5.43,9],
                   [3.44,5.43,1], ])
print ('T1 shape',T1.shape) # -&gt; T1 shape torch.Size([6, 3]) 
for i in range(T1.shape[0]):
    key = ''.join([ str(int(j)) for j in T1[i].tolist()]) # creates a unique identifier (is there a better way to do this?)
    if key in od:
        od[key] +=1
        key_place_holder = key + str(od[key]) # unique identifier if we found duplicate to keep a 0 in the final tensor
        od[key_place_holder] = 0
    else:
        od[key] = 1
print ('len od',len(od)) # -&gt; len od 6
list_values = [j/len(od) for i,j in od.items()] 
T1_marginal_probabilities = torch.Tensor(list_values)
print ('Marginal Probs',T1_marginal_probabilities) # -&gt; Marginal Probs tensor([0.3333, 0.3333, 0.0000, 0.1667, 0.1667, 0.0000])

The final output is as expected, as the probability of [2.4, 5.5,1] and [3.44,5.43,1] are both 2/6, since we have [2.4, 5.5,1] repeated 2 times at position 0 and 2. while [3.44,5.43,1] is repeated in position 1 and 5.

You can use torch.unique and torch.nonzero:
T1 = ...
values, inverse, counts = T1.unique(dim=0, return_inverse=True, return_counts=True)

ps = torch.zeros(inverse.numel())
for i, (v, c) in enumerate(zip(values, counts)):
    first_occurence = torch.nonzero(inverse == i)[0].item()
    ps[first_occurence] = c
ps /= ps.sum()

