Finite difference is a numerical method to approximate a derivative.
There are mainly three types of finite difference method: central,
forward and backward.
In this question, I will introduce central difference method. we can
approximate f '(x) by: f'(x)=(f(x+h)-f(x-h))/2h. Write a code to
calculate the first derivative of sin(x) at x=0 with h=1, 0.1,
0.01 and 0.001. Also compare the result with cos(0) (to use function “cos()”, you should import “math” first).
Draw a graph to compare the result of different h value, x axis is the
value of h and y1 axis is the calculated first derivative of sin(x)
and y2 is the result of cos(0).
#!/usr/bin/env python
import math
def f(x):
return sin(x)
def derivative(0,h=1)
deriv = (f(x + h) - f(x - h))/ 2 * h
return round(deriv, 0)
print "f'(x)=", derivative(0)
Can anyone give me some suggestions?
Your main problem is you are dividing by 2 * h, this means divide by 2, then multiply by h. You need to divide by (2 * h). You might have learned the BODMAS rules in school.
>>> 12 / 2 * 3
18
That divides 12 by 2 to get 6, then multiplies 6 by 3. If you group (2 * 3) using parentheses, the whole multiplication operation will be evaluated first:
>>> 12 / (2 * 3)
2
Fixed code:
def f_dash(f, x, h):
return (f(x + h) - f(x - h)) / (2 * h)
>>> from math import sin, cos
>>> f_dash(f=sin, x=0, h=0.1)
0.9983341664682815
>>> f_dash(sin, 0, 0.001)
0.9999998333333416
Related
I have this python code for finding intersections in the function "f(x)=x**2+x-2" with "g(x)=6-x"
import math
#brute force the functions with numbers until his Y values match, and then, do this for the other point.
def funcs():
for X in range(-100, 100):
funcA = (X**2)+X-2
funcB = 6 - X
if funcA == funcB:
print("##INTERSECTION FOUND!!")
print(f"({X},{funcA})")
print(f"({X},{funcB})")
else:
pass
funcs()
But my problem is the script only works with THAT SPECIFIC MATH FUNCTION, if I try to change the math function a little bit, the code won't work.
The code just checks when the Y values of the f(x) and the g(x) match together, and do the same for the other point.
Here it is the output:
##INTERSECTION FOUND!!
(-4,10)
(-4,10)
##INTERSECTION FOUND!!
(2,4)
(2,4)
In general, this is a root finding problem.
Define h(x) = f(x) - g(x).
The intersection point x implies f(x)=g(x) or h(x)=0.
For root-finding problems, there are many methods, say, bisection method, newton's method.
Here is a numerical example with bisection method.
def f(x):
return x ** 2 + x - 2
def g(x):
return 6 - x
def h(x):
return f(x) - g(x)
def bisection(a, b):
eps = 10 ** -10
ha = h(a)
hb = h(b)
if ha * hb > 0:
raise ValueError("Bad input")
for i in range(1000): # fix iteration number
ha = h(a)
midpoint = (a + b) / 2
hm = h(midpoint)
if abs(hm) < eps:
return midpoint
if hm * ha >= 0:
a = midpoint
else:
b = midpoint
raise RuntimeError("Out of iterations")
if __name__ == '__main__':
print(bisection(0, 100))
print(bisection(-100, 0))
Output:
1.999999999998181
-3.999999999996362
Why the numbers so close but not exact? because the problem is solved numerically. Other answers that utilize the sympy package solves the problem symbolically, which give the exact answer. But they only work with simple problems.
Why [0, 100] and [-100, 0]? this is because I sketched the graph somehow and know there is a root within the interval. In practice, the bisection method requires the interval [a,b] such that h(a) * h(b) < 0. Given a big interval [-100,100] and, thus, h(-100) * h(100) > 0, bisection method does not work this case. The big interval is partitioned such that some of the sub-intervals [a,b] satisfy the condition h(a) * h(b) < 0, say, [-100, 0] and [0, 100]
Why abs(hm) < eps? This tests whether hm is close to 0. In computers, we consider two floating-point numbers equal if the absolute value of their difference abs(hm) is smaller than a threshold eps. eps is usually 10 ** -10 to 10 ** -15 because there are usually 15 decimal significant digits for float numbers in Python or computer.
Newton's method will give you one of the outputs depending on the initial point.
For further study, search root finding problem or numerical root finding.
As you want the intersection, hence you are looking for a solution for f(x) - g(x) = 0. So, you can use fsolve in python to find the root of f(x) - g(x):
from scipy.optimize import fsolve
def func(X):
funcA = (X ** 2) + X - 2
funcB = 6 - X
return (funcA - funcB)
x = fsolve(func,0)
print(x)
You could employ sympy, Python's symbolic math library:
from sympy import symbols, Eq, solve
X = symbols('X', real=True)
funcA = (X ** 2) + X - 2
funcB = 6 - X
sol = solve(Eq(funcA, funcB))
print(sol) # --> [-4, 2]
To obtain the corresponding values for funcA and funcB
for s in sol:
print(f'X={s} funcA({s})={funcA.subs(X, s)} funcB({s})={funcB.subs(X, s)} ')
# X=-4 funcA(-4)=10 funcB(-4)=10
# X=2 funcA(2)=4 funcB(2)=4
For some functions, the result could still be symbolically, as that is the most exact form. .evalf() obtains a numeric approximation. For example:
funcA = X ** 2 + X - 2
funcB = - 2*X ** 2 + X + 7
sol = solve(Eq(funcA, funcB))
for s in sol:
print(f'X={s} funcA(X)={funcA.subs(X, s)} funcB(X)={funcB.subs(X, s)}')
print(f'X={s.evalf()} funcA(X)={funcA.subs(X, s).evalf()} funcB(X)={funcB.subs(X, s).evalf()}')
Output:
X=-sqrt(3) funcA(X)=1 - sqrt(3) funcB(X)=1 - sqrt(3)
X=-1.73205080756888 funcA(X)=-0.732050807568877 funcB(X)=-0.732050807568877
X=sqrt(3) funcA(X)=1 + sqrt(3) funcB(X)=1 + sqrt(3)
X=1.73205080756888 funcA(X)=2.73205080756888 funcB(X)=2.73205080756888
I'm tring to approximate an empirical cumulative distribution function (ECDF I want to approximate) with a smooth function (with less than 5 parameter) such as the generalized logistic function.
However, using scipy.optimize.curve_fit, the fitting operation gives really bad approximations or it doesn't work at all (depending on the initial values). The variable series represents my data stored as pandas.Series.
from scipy.optimize import curve_fit
def fit_ecdf(x):
x = np.sort(x)
def result(v):
return np.searchsorted(x, v, side='right') / x.size
return result
ecdf = fit_ecdf(series)
def genlogistic(x, B, M, Q, v):
return 1 / (1 + Q * np.exp(-B * (x - M))) ** (1 / v)
params = curve_fit(genlogistic, xdata = series, ydata = ecdf(series), p0 = (0.1, 10.0, 0.1, 0.1))[0]
Should I use another type of function for the fit?
Are there any code mistakes?
UPDATE - 1
As asked, I link to a csv containing the data.
UPDATE - 2
After a lot of search and trial and error I find out this function
f(x; a, b, c) = 1 - 1 / (1 + (x / b) ** a) ** c
with a = 4.61320000, b = 2.94570952, c = 0.5886922
which fits a lot better than the other one. The only problem is the little step that the ECDF shows near x=1. How can I modify f to improve the quality of the fit? I was thinking of adding some sort of function that is "relevant" only in those kind of points. Here are the graphical results of the fit where the solid blue line is the ECDF and the dotted line represents the (x, f(x)) points.
I find out how to deal with that little step near x=1. As expressed in the question, adding some sort of function that is significant only in that interval was the game changer.
The "step" ends at about (1.7, 0.04) so I needed a sort of function that flattens for x > 1.7 and has y = 0.04 as asymptote. The natural choice (just to stay on point) was to take a function like f(x) = 1/exp(x).
Thanks to JamesPhillips, I also picked up the proper data for the regression (no double values = no overweighted points).
Python Code
from scipy.optimize import curve_fit
def fit_ecdf(x):
x = np.sort(x)
def result(v):
return np.searchsorted(x, v, side = 'right') / x.size
return result
ecdf = fit_ecdf(series)
unique_series = series.unique().tolist()
def cdf_interpolation(x, a, b, c, d):
f_1 = 0.95 + (0 - 0.95) / (1 + (x / b) ** a) ** c + 0.05
f_2 = (0 - 0.05)/(np.exp(d * x))
return f_1 + f_2
params = curve_fit(cdf_interpolation,
xdata = unique_series ,
ydata = ecdf(unique_series),
p0 = (6.0, 3.0, 0.4, 1.0))[0]
Parameters
a = 6.03256462
b = 2.89418871
c = 0.42997956
d = 1.06864006
Graphical results
I got an OK fit for a 5-parameter logistic equation (see image and code) using unique values, not sure if the low end curve is sufficient for your needs, please check.
import numpy as np
def Sigmoidal_FiveParameterLogistic_model(x_in): # from zunzun.com
# coefficients
a = 9.9220221252324947E-01
b = -3.1572339989462903E+00
c = 2.2303376075685142E+00
d = 2.6271495036080207E-02
f = 3.4399008905318986E+00
return d + (a - d) / np.power(1.0 + np.power(x_in / c, b), f)
I am reading Data Science From Scratch by Joel Grus, and am stuck on understanding how a simple difference quotient function works using python.
Here is the code:
f is a function of a one variable function, dependent on x, as h approaches 0.
def difference_quotient(f, x, h):
return (f(x + h) - f(x)) / h
I understand that this is just the equation for finding the limit, and in this case the derivative, but I don't see how the script works. What arguments would you put into the function that would allow for a return statement of f(something) and not f*(something). So far I keep getting errors such as 'float'/'dict' object is not callable.
f is the function you are trying to find the derivative/difference quotient of at x.
Try this code: (python 3)
def difference_quotient(f, x, h):
return (f(x + h) - f(x)) / h
def func(x):
# this is f of x, the function you are taking the derivative of
return x * x
print(difference_quotient(func, 2, 0.001))
"Someone" has answered your question but you (and future readers) may find this supplementary information useful.
To get an accurate approximation of the derivative you need to make h fairly small. However, if you make it too small then you actually lose accuracy due to the limited precision of Python floats. You can get more precision by using the decimal module. However, that module only supports simple arithmetic operators and the square root function. If you need fancier functions like trigonometric or exponential functions, then you can use a 3rd-party package arbitrary-precision mathemtaics package such as the excellent mpmath, although if you do use mpmath then you'd probably use its numerical derivative functions.
FWIW, you can make the derivative approximation more accurate (for a given h) by making x the middle of the interval. Here's a short demo:
def dfa(f, x, h):
return (f(x + h) - f(x)) / h
def dfb(f, x, h):
hh = 0.5 * h
return (f(x + hh) - f(x - hh)) / h
# The function
def func(x): return x**3 + x*x + x + 1
# Its exact derivative
def dfunc(x): return 3*x*x + 2*x + 1
h = 0.001
for i in range(10):
x = 1 + 0.1 * i
print(x, dfunc(x), dfb(func, x, h), dfa(func, x, h))
output
1.0 6.0 6.00000024999936 6.004000999999093
1.1 6.830000000000001 6.830000249999024 6.8343009999995985
1.2 7.719999999999999 7.72000024999997 7.724600999999609
1.3 8.67 8.670000249998644 8.674900999999124
1.4 9.68 9.680000249999487 9.685200999998145
1.5 10.75 10.750000249998948 10.755500999998446
1.6 11.880000000000003 11.880000249998801 11.885800999996476
1.7000000000000002 13.070000000000002 13.07000024999816 13.07610099999934
1.8 14.32 14.320000249997022 14.326400999998157
1.9 15.629999999999999 15.630000249997167 15.636700999996478
Here are the results for the exponential function.
from math import exp
def dfa(f, x, h):
return (f(x + h) - f(x)) / h
def dfb(f, x, h):
hh = 0.5 * h
return (f(x + hh) - f(x - hh)) / h
func = dfunc = exp
h = 0.001
for i in range(10):
x = 1 + 0.1 * i
print(x, dfunc(x), dfb(func, x, h), dfa(func, x, h))
output
1.0 2.718281828459045 2.718281941720413 2.7196414225332255
1.1 3.0041660239464334 3.0041661491195804 3.005668607777512
1.2 3.3201169227365472 3.320117061074157 3.3217775346887635
1.3 3.6692966676192444 3.669296820505874 3.6711319276547805
1.4 4.0551999668446745 4.0552001358102885 4.057228242863253
1.5 4.4816890703380645 4.481689257074706 4.483930662008362
1.6 4.953032424395115 4.953032630771403 4.955509766318755
1.7000000000000002 5.473947391727201 5.473947619807795 5.476685277975513
1.8 6.0496474644129465 6.049647716480422 6.0526732966712515
1.9 6.6858944422792685 6.685894720857455 6.689238504094419
Note that dfb is not foolproof: if you're trying to find the derivative for an x value that's near a pole or discontinuity, then shifting the interval to include the pole or discontinuity can give erroneous results. Of course, you can get the same problem with dfa, eg if f(x) = 1/x and x is a negative number but x+h is positive.
I try to make this simple program to compute the derivative of a function with normal precision:
# second derivative of a function
def diff2(f, x, h=1E-6):
r = (f(x-h) - 2*f(x) + f(x+h))/float(h*h)
return r
# define the function to derivate
def g(t):
return t**(-6)
# decresing h increasing the precision of the derivative
# ROUND-OFF problems are present
for k in range(1,15):
h = 10**(-k) # 15 different value of h
d2g = diff2(g, 1, h) # compute d'' of g 15-th times in point t=1
print 'h=%.0e: %.5f' % (h, d2g)
As one can see from the printing operation I have problem when k is larger than 8 due to round off. I know I can use:
from decimal import *
But I do not know how to implement these command in my functions.
Could someone help me please?
It is worth looking into the python module mpmath, which can handle arbitrary precision. For example:
>>> from mpmath import mp
>>> mp.dps = 50
>>> print(mp.quad(lambda x: mp.exp(-x**2), [-mp.inf, mp.inf]) ** 2)
3.1415926535897932384626433832795028841971693993751
You could simply change types and let your functions work with greater precision. It is worth noting the comments and the answer by #halex however.
If you want the derivative at position x_0 and perform your calculation with floats the optimal value for h which minimizes the numerical error is sqrt(sys.float_info.epsilon)*x_0 which is approximately 1E-8 for your case where x_0=1.
For further information and a derivation of this value see the chapter How to Choose hstarting at page 4 until the end in this short script on Numerical Differentiation.
You can use the decimal module:
from decimal import Decimal
# second derivative of a function
def diff2(f, x, h=1E-6):
x, h = Decimal(x), Decimal(h)
r = (f(x - h) - 2 * f(x) + f(x + h)) / Decimal(h * h)
return r
I'm new with Python, and started to work on a Coordinate Conversion program. The problem is that I can't find an iterative method to solve one of the expressions.
Expressions:
N = a / math.sqrt(1 - (e2 * (math.sin(phi))**2))
phi = math.atan((Z / math.sqrt((X**2) + (Y**2))) * ((1-e2) * (N / N + hei)**-1))
lam = math.atan(Y / X)
hei = (math.sqrt((X ** 2) + (Y ** 2))) / math.cos(phi)
Here, a and e2 are constants.
The user is supposed to introduce the values of X, Y and Z and obtain phi, lam and hei. But, given that N is a function that depends of phi, it is necessary to create a loop, making hei = 0 in the second equation as an initial value, in order to procure a first approximation for phi. However, I don't know how to end that cycle when phi has reached a certain value (for instance, when 9 or more of the decimals of phi are equal to the previous value in the loop).
You could break the loop based on the difference between the value of phi in the previous loop and that in the current loop, i.e. if the difference is smaller than 10^(-9).