Было бы неплохо, если бы вы предоставили некоторые данные для работы. Неважно, мы их создадим.
Давайте создадим значения x, y из r, theta произвольные значения:
import numpy as np
import matplotlib.pyplot as plt
theta=np.linspace(0.,50.,1000)
r=np.linspace(5.,10,1000)
x=r*np.sin(theta)
y=r*np.cos(theta)
plt.plot(x,y,linestyle='',marker='.')
График дает:

Now add arbitrary intensity values :
intensity=np.sqrt(x**2+y**2)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x, y, intensity)
The scatter plot gives :

If I understand well we should not be far from your starting point. We have now 3 arrays with 1000 values. We are going to reduce it to a 20x20 mesgrid.
We have to first create the x and y bins, then call the binned_statistic_2d method from scipy and that's it.
import scipy.stats as stats
binx=np.linspace(-10.,10.,20)
biny=np.linspace(-10.,10.,20)
ret = stats.binned_statistic_2d(x, y, intensity, 'mean', bins=[binx,biny])
Z=ret.statistic
Z = np.ma.masked_invalid(Z) # allow to mask Nan values got in bins where there is no value
X, Y = np.meshgrid(binx,biny)
plt.pcolor(X,Y,Z)
plt.show()
The pcolor plot gives :

As requested in your comment, we can now go back to the original x,y,z arrays structure.
First, we have to calculate the center coordinates of the bins
binx_centers=(binx[1:] + binx[:-1])/2
biny_centers=(biny[1:] + biny[:-1])/2
Xcenters, Ycenters = np.meshgrid(binx_centers,biny_centers)
Then we can get the not masked values (see explanation above)
xnew=np.ma.masked_array(Xcenters, Z.mask).compressed()
ynew=np.ma.masked_array(Ycenters, Z.mask).compressed()
znew=Z.compressed()
We can check the new size :
print(znew.shape)
Gives only 235 values (instead of 1000.):
(235L,)
And the new scatter plot with the compressed values :
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(xnew, ynew, znew)
We obtain :
введите описание изображения здесь