2

Given an Array of Points

points = np.array([[1,1,1], [0,1,1], [1,0,0], [1,1,1]])

create an array that counts the coordinates, meaning:

r = [[0,0],  [[1,0],
     [0,1]],  [0,2]]

meaning the coordinate [1,1,1] exists twice so a the position [1,1,1] there is a 2 in the resulting array.

In plain python this would be:

for p in points:
    r[p[0]][p[1]][p[2]] += 1

I need this in the context of an realtime application, there are up to 300k points given per frame and a resulting matrix shape of up to 400x400x400, so speed is important. the amount of points and shape of the resulting matrix change dynamically.

I am new to numpy and have not found an efficient way to do this, doing it with a plain python for loop is too slow taking up to a second per frame.

Michael Szczesny
  • 4,911
  • 5
  • 15
  • 32
erikgo
  • 31
  • 4
  • 1
    It's not clear what the connection is between the starting array of points and the result. Your sentence "meaning the coordinate [1,1,1] exists twice so a the position [1,1,1] there is a 2 in the resulting array" is difficult to make sense of – Ben Grossmann Dec 25 '22 at 22:32
  • 1
    It would be helpful if you could edit your question to paste in the for loop you wrote. That way, we could at least unambiguously understand what logic this result is supposed to follow – Ben Grossmann Dec 25 '22 at 22:34
  • @BenGrossmann question is updated, i hope its easier to understand now – erikgo Dec 25 '22 at 22:38
  • Yes, much clearer, thank you – Ben Grossmann Dec 25 '22 at 22:39

2 Answers2

3

Consider the following.

points = np.array([[1,1,1], [0,1,1], [1,0,0], [1,1,1]])

unique, counts = np.unique(points, return_counts = True, axis = 0)
n = 1+np.max(unique)
r = np.zeros([n,n,n], dtype = int)
r[tuple(unique.T)] = counts

(Note: the final line above is equivalent to r[unique[:,0],unique[:,1],unique[:,2]] = counts).

Resulting array r:

[[[0 0]
  [0 1]]

 [[1 0]
  [0 2]]]
Ben Grossmann
  • 4,387
  • 1
  • 12
  • 16
  • @erikgo If you don't mind answering, it'd be helpful for me to know: is there a reason that you found the other answer more useful? – Ben Grossmann Dec 27 '22 at 18:42
2

You can ravel the 3D coordinates to 1D offsets with np.ravel_multi_index and count these using np.bincount.

import numpy as np

points = np.array([[1,1,1], [0,1,1], [1,0,0], [1,1,1]])

m = points.max(0)+1
np.bincount(np.ravel_multi_index(points.T, m), minlength=np.prod(m)).reshape(m)

Output

array([[[0, 0],
        [0, 1]],

       [[1, 0],
        [0, 2]]])
Michael Szczesny
  • 4,911
  • 5
  • 15
  • 32