I'm just spitballing here ... (since I don’t have time to actually try this) ...
Your data looks (roughly) linear on the log chart (at least each segment seems ... So, I could consider integrating into the log space.
log_x = log(x) log_y = log(y)
Now, for each of your points, you can get the slope (and interception) in the log-log space:
rise = np.diff(log_y) run = np.diff(log_x) slopes = rise / run
And, similarly, the interception can be calculated:
# y = mx + b
Ok, now we have a bunch of (direct) lines in the log-log space. But the straight line in the log-log space corresponds to y = log(intercept)*x^slope in real space. We can easily integrate this: y = a/(k+1) x ^ (k+1) , so ...
def _eval_log_log_integrate(a, k, x): return np.log(a)/(k+1) * x ** (k+1) def log_log_integrate(a, k, x1, x2): return _eval_log_log_integrate(a, k, x2) - _eval_log_log_integrate(a, k, x1) partial_integrals = [] for a, k, x_lower, x_upper in zip(intercepts, slopes, x[:-1], x[1:]): partial_integrals.append(log_log_integrate(a, k, x_lower, x_upper)) total_integral = sum(partial_integrals)
You want to check my math - some time has passed since I did such things :-)