How do I to average irregularly spaced x & y coordinate tensor into a grid with a specific cell size?
I have an algorithm that generates a tensor of irregularly spaced x and y coordinates (ex: torch.size([3600, 2])), and I need to average the points into grid cells of a specific size (ex: 8 by 8). The resulting grid needs to be either an array or tensor.
It's not required, but I would also like to be able to determine if any of the resulting cells have less than a specified number of points in them.
For example I can graph the tensor using matplotlib's plt.scatter, and it looks like this:

In the above example, 100,000 points exist but the number of points can sometimes be in the tens of millions.
I've tried using histogram approaches, and most of them use a specific number of cells vs a specific cell size. Matplotlib can seemingly do it in a graph, but that doesn't help me get an array or tensor.
Edit:
This code might work, if it can be made to work properly.
def grid_torch(x_coords, y_coords, grid_size=(8,8), x_extent=(0., 1.), y_extent=(0., 1.)):
    x_coords = ((x_coords - x_extent[0]) / (x_extent[1] - x_extent[0])) * grid_size[0]
    y_coords = ((y_coords - y_extent[0]) / (y_extent[1] - y_extent[0])) * grid_size[1]

    x_list = []
    for x in range(grid_size[0]):
        x = torch.ones_like(x_coords) * x
        y_list = []
        for y in range(grid_size[1]):
            y = torch.ones_like(y_coords) * y
            in_bounds_x = torch.logical_and(x &lt;= x_coords, x_coords &lt;= x + 1)
            in_bounds_y = torch.logical_and(y &lt;= y_coords, y_coords &lt;= y + 1)
            in_bounds = torch.logical_and(in_bounds_x, in_bounds_y)

            in_bounds_indices = torch.where(in_bounds)
            print(in_bounds_indices)
            y_list.append(in_bounds_indices)
        x_list.append(torch.stack(y_list))
    return torch.stack(x_list)



out = grid_torch(xy_tensor[:,0], xy_tensor[:,1])

print(out.shape)

def create_grid(grid_layout, activ, grid_size=(8,8), min_density=8):
    cells = []
    for x in range(grid_size[0]):
        for y in range(grid_size[1]):
            indices = grid_layout[x, y]
            if len(indices) &gt; min_density:
                average_activation = torch.mean(activ[indices])
                cells.append((average_activation, x, y))
                print(average_activation, x, y)
    return torch.stack(cells)



grid_test = create_grid(out, xy_tensor, grid_size=(8,8))


I think this code would give you a good starting point.
def grid_torch(x_coords, y_coords, grid_size=(8,8), x_extent=(0., 1.), y_extent=(0., 1.)):
    # This part converts coordinates to bin numbers (like (2,5), (7,7) etc)
    x_bin = (((x_coords - x_extent[0]) / (x_extent[1] - x_extent[0])) * grid_size[0]).int()
    y_bin = (((y_coords - y_extent[0]) / (y_extent[1] - y_extent[0])) * grid_size[1]).int()
    
    counts = torch.zeros(grid_size)
    means = torch.zeros(list(grid_size) + [2])
    for x in range(grid_size[0]):
        for y in range(grid_size[1]):
            # these tensors are 1 where (x_bin == x and y_bin == y), 0 else where
            x_where = 1 * (x_bin == x)
            y_where = 1 * (y_bin == y)
            p_where = (x_where * y_where)
            cnt = p_where.sum()
            counts[x, y] = cnt
            
            # we'll average both x and y coords seperately.
            # you can embed min_density logic here. 
            if cnt &gt; 0:
                means[x, y, 0] = (x_coords * p_where).sum() / p_where.sum()
                means[x, y, 1] = (y_coords * p_where).sum() / p_where.sum()
    
    return counts, means


# Generate sample points
points = torch.tensor(np.concatenate([
    np.random.normal(loc=0.2, scale=0.1, size=(1000, 2)),
    np.random.normal(loc=0.6, scale=0.1, size=(1000, 2))
]).clip(0,1)).float()
# plt.scatter(points[:,0], points[:,1])
# plt.grid()

counts, means = grid_torch(points[:,0], points[:,1])
counts

&gt;&gt;&gt;
tensor([[ 47., 114.,  75.,  10.,   0.,   0.,   0.,   0.],
        [102., 204., 141.,  27.,   0.,   0.,   0.,   0.],
        [ 60., 101.,  74.,  16.,   7.,   4.,   1.,   0.],
        [  5.,  17.,   9.,  23.,  72.,  51.,  10.,   0.],
        [  1.,   1.,   4.,  54., 186., 141.,  28.,   3.],
        [  0.,   0.,   3.,  47., 154., 117.,  14.,   0.],
        [  0.,   0.,   0.,   9.,  37.,  24.,   4.,   0.],
        [  0.,   0.,   0.,   2.,   0.,   1.,   0.,   0.]])


