Adams Gwazah
Adams Gwazah

Reputation: 421

How do I compute the derivative of an array in python

How do I compute the derivative of an array, y (say), with respect to another array, x (say) - both arrays from a certain experiment?

e.g.

y = [1,2,3,4,4,5,6] and x = [.1,.2,.5,.6,.7,.8,.9];

I want to get dy/dx!

Upvotes: 42

Views: 168505

Answers (4)

imbr
imbr

Reputation: 7632

1. Use numpy.gradient (best option)

Most people want this. This is now the Numpy provided finite difference aproach (2nd-order accurate.) Same shape-size as input array.

Uses second order accurate central differences in the interior points and either first or second order accurate one-sides (forward or backwards) differences at the boundaries. The returned gradient hence has the same shape as the input array.

2. Use numpy.diff (you probably don't want this)

If you really want something ~twice worse this is just 1st-order accurate and also doesn't have same shape as input. But it's faster than above (some little tests I did).

For constant space between x sampless

import numpy as np 
dx = 0.1; y = [1, 2, 3, 4, 4, 5, 6] # dx constant
np.gradient(y, dx) # dy/dx 2nd order accurate
array([10., 10., 10.,  5.,  5., 10., 10.])

For irregular space between x samples

your question

import numpy as np
x = [.1, .2, .5, .6, .7, .8, .9] # dx varies
y = [1, 2, 3, 4, 4, 5, 6]
np.gradient(y, x) # dy/dx 2nd order accurate
array([10., 8.333..,  8.333.., 5.,  5., 10., 10.])

What are you trying to achieve?

The numpy.gradient offers a 2nd-order and numpy.diff is a 1st-order approximation schema of finite differences for a non-uniform grid/array. But if you are trying to make a numerical differentiation, a specific finite differences formulation for your case might help you better. You can achieve much higher accuracy like 8th-order (if you need) much superior to numpy.gradient.

Upvotes: 53

giotto
giotto

Reputation: 622

use numpy.gradient()

Please be aware that there are more advanced way to calculate the numerical derivative than simply using diff. I would suggest to use numpy.gradient, like in this example.

import numpy as np
from matplotlib import pyplot as plt

# we sample a sin(x) function
dx = np.pi/10
x = np.arange(0,2*np.pi,np.pi/10)

# we calculate the derivative, with np.gradient
plt.plot(x,np.gradient(np.sin(x), dx), '-*', label='approx')

# we compare it with the exact first derivative, i.e. cos(x)
plt.plot(x,np.cos(x), label='exact')
plt.legend()

Upvotes: 24

user3554809
user3554809

Reputation: 71

numpy.diff(x) computes

the difference between adjacent elements in x

just like in the answer by @tsm. As a result you get an array which is 1 element shorter than the original one. This of course makes sense, as you can only start computing the differences from the first index (1 "history element" is needed).

>>> x = [1,3,4,6,7,8]
>>> dx = numpy.diff(x)
>>> dx
array([2, 1, 2, 1, 1])

>>> y = [1,2,4,2,3,1]
>>> dy = numpy.diff(y)
>>> dy
array([ 1,  2, -2,  1, -2])

Now you can divide those 2 resulting arrays to get the desired derivative.

>>> d = dy / dx
>>> d
array([ 0.5,  2. , -1. ,  1. , -2. ])

If for some reason, you need a relative (to the y-values) growth, you can do it the following way:

>>> d / y[:-1]
array([ 0.5       ,  1.        , -0.25      ,  0.5       , -0.66666667])

Interpret as 50% growth, 100% growth, -25% growth, etc.

Full code:

import numpy
x = [1,3,4,6,7,8]
y = [1,2,4,2,3,1]
dx = numpy.diff(x)
dy = numpy.diff(y)
d = dy/dx

Upvotes: 4

tsm
tsm

Reputation: 3658

I'm assuming this is what you meant:

>>> from __future__ import division
>>> x = [.1,.2,.5,.6,.7,.8,.9]
>>> y = [1,2,3,4,4,5,6]
>>> from itertools import izip
>>> def pairwise(iterable): # question 5389507
...     "s -> (s0,s1), (s2,s3), (s4, s5), ..."
...     a = iter(iterable)
...     return izip(a, a)
... 
>>> for ((a, b), (c, d)) in zip(pairwise(x), pairwise(y)):
...   print (d - c) / (b - a)
... 
10.0
10.0
10.0
>>>

question 5389507 link

That is, define dx as the difference between adjacent elements in x.

Upvotes: 5

Related Questions