I benchmarked a numexpr version against a simple Numpy implementation as follows:
#!/usr/bin/env python3
import numpy as np
import numexpr as ne
# Ensure repeatable, deterministic randomness!
np.random.seed(42)
# Generate test arrays
N = 1000000
X = np.random.rand(N)
Y = np.random.rand(N)
# Define centre and radius
cx = cy = r = 0.5
def method1(X,Y,cx,cy,r):
"""Straight Numpy determination of points in circle"""
d = (X-cx)**2 + (Y-cy)**2
res = d < r**2
return res
def method2(X,Y,cx,cy,r):
"""Numexpr determination of points in circle"""
res = ne.evaluate('((X-cx)**2 + (Y-cy)**2)<r**2')
return res
def method3(data,a,b,r):
"""List based determination of points in circle, with pre-filtering using a square"""
in_square_points = [(x,y) for (x,y) in data if a-r < x < a+r and b-r < y < b+r]
in_circle_points = [(x,y) for (x,y) in in_square_points if (x-a)**2 + (y-b)**2 < r**2]
return in_circle_points
# Timing
%timeit method1(X,Y,cx,cy,r)
%timeit method2(X,Y,cx,cy,r)
# Massage input data (before timing) to match agorithm
data=[(x,y) for x,y in zip(X,Y)]
%timeit method3(data,cx,cy,r)
I then timed it in IPython as follows:
%timeit method1(X,Y,cx,cy,r)
6.68 ms ± 246 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit method2(X,Y,cx,cy,r)
743 µs ± 17.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit method3(data,cx,cy,r)
1.11 s ± 9.81 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
So the numexpr version came out 9x faster. As the points lie in the range [0..1], the algorithm is effectively calculating pi and the two methods come out the same:
method1(X,Y,cx,cy,r).sum()
784973
method2(X,Y,cx,cy,r).sum()
784973
len(method3(data,cx,cy,r))
784973
4 * 784973 / N
3.139
Note: I should point out that numexpr multi-threads your code across multiple CPU cores for you, automatically. If you feel like experimenting, with the number of threads, you can change it dynamically before calling method2(), or even inside there, with:
# Split calculations across 6 threads
ne.set_num_threads(6)
Anyone else wishing to test the speed of their method is welcome to use my code as a benchmarking framework.