Làm cách nào để tính toán phái sinh bằng Numpy?


91

Làm cách nào để tính đạo hàm của một hàm, chẳng hạn

y = x 2 +1

sử dụng numpy?

Giả sử, tôi muốn giá trị của đạo hàm tại x = 5 ...


5
Bạn cần phải sử dụng Sympy: sympy.org/en/index.html NumPy là một thư viện tính toán số cho Python
prrao

Ngoài ra, bạn có muốn một phương pháp để ước tính giá trị số của đạo hàm không? Đối với điều này, bạn có thể sử dụng một phương pháp chênh lệch hữu hạn, nhưng hãy nhớ rằng chúng có xu hướng ồn ào khủng khiếp.
Henry Gomersall

Câu trả lời:


142

Bạn có bốn lựa chọn

  1. Sự khác biệt hữu hạn
  2. Phái sinh tự động
  3. Sự khác biệt mang tính biểu tượng
  4. Tính toán các dẫn xuất bằng tay.

Sự khác biệt hữu hạn không yêu cầu công cụ bên ngoài nhưng dễ bị sai số và nếu bạn đang ở trong tình huống đa biến, có thể mất một lúc.

Sự khác biệt mang tính biểu tượng là lý tưởng nếu vấn đề của bạn đủ đơn giản. Những ngày này, các phương pháp tượng trưng đang trở nên khá mạnh mẽ. SymPy là một dự án tuyệt vời để tích hợp tốt với NumPy. Xem các chức năng autowrap hoặc lambdify hoặc xem bài đăng trên blog của Jensen về một câu hỏi tương tự .

Các dẫn xuất tự động rất tuyệt, không dễ bị lỗi số, nhưng yêu cầu một số thư viện bổ sung (google cho điều này, có một vài tùy chọn tốt). Đây là sự lựa chọn mạnh mẽ nhất nhưng cũng phức tạp / khó thiết lập nhất. Nếu bạn chỉ giới hạn bản thân với numpycú pháp thì Theano có thể là một lựa chọn tốt.

Đây là một ví dụ sử dụng SymPy

In [1]: from sympy import *
In [2]: import numpy as np
In [3]: x = Symbol('x')
In [4]: y = x**2 + 1
In [5]: yprime = y.diff(x)
In [6]: yprime
Out[6]: 2x

In [7]: f = lambdify(x, yprime, 'numpy')
In [8]: f(np.ones(5))
Out[8]: [ 2.  2.  2.  2.  2.]

Xin lỗi, nếu điều này có vẻ ngu ngốc, Sự khác biệt giữa 3.Symbolic Differentiation và 4.by hand difference là gì ??
DrStrangeLove

11
Khi tôi nói "sự khác biệt tượng trưng", tôi có ý ám chỉ rằng quá trình này được xử lý bởi một máy tính. Về nguyên tắc 3 và 4 chỉ khác nhau bởi ai thực hiện công việc, máy tính hoặc người lập trình. 3 được ưu tiên hơn 4 do tính nhất quán, khả năng mở rộng và sự lười biếng. 4 là cần thiết nếu 3 không tìm ra giải pháp.
MRocklin

4
Trong dòng 7, chúng tôi đã tạo f, một hàm tính đạo hàm của y wrt x. Trong 8, chúng ta áp dụng hàm đạo hàm này cho một vectơ của tất cả các cái và nhận được vectơ của tất cả các cặp. Điều này là do, như đã nêu ở dòng 6, yprime = 2 * x.
MRocklin

Chỉ vì mục đích đầy đủ, bạn cũng có thể phân biệt bằng tích phân (xem công thức tích phân Cauchy), nó được thực hiện ví dụ như trong mpmath(không chắc chắn nhưng chúng chính xác là gì).
DerWeh

Có cách nào dễ dàng để thực hiện sự khác biệt hữu hạn trong numpy mà không cần tự thực hiện nó không? Ví dụ: tôi muốn tìm gradient của một hàm tại các điểm được xác định trước.
Alex

41

Cách dễ hiểu nhất mà tôi có thể nghĩ đến là sử dụng hàm gradient của numpy :

x = numpy.linspace(0,10,1000)
dx = x[1]-x[0]
y = x**2 + 1
dydx = numpy.gradient(y, dx)

Bằng cách này, dydx sẽ được tính bằng cách sử dụng các khác biệt trung tâm và sẽ có cùng độ dài với y, không giống như numpy.diff, sử dụng chênh lệch chuyển tiếp và sẽ trả về vectơ kích thước (n-1).


2
Điều gì xảy ra nếu dx không phải là hằng số?
weberc2

3
@ weberc2, trong trường hợp đó, bạn nên chia một vectơ này cho một vectơ khác, nhưng xử lý các cạnh riêng biệt với các đạo hàm tiến và lùi theo cách thủ công.
Sparkler

2
Hoặc bạn có thể nội suy y với một hằng số dx, sau đó tính gradient.
IceArdor

@Sparkler Cảm ơn đề xuất của bạn. Nếu tôi có thể hỏi 2 câu hỏi nhỏ, (i) tại sao chúng tôi chuyển dxcho numpy.gradientthay vì x? (ii) Chúng tôi cũng có thể làm dòng cuối cùng của bạn như sau dydx = numpy.gradient(y, numpy.gradient(x)):?
user929304

2
Kể từ v1.13, khoảng cách không đồng nhất có thể được chỉ định bằng cách sử dụng một mảng làm đối số thứ hai. Xem phần Ví dụ của trang này .
Nathaniel Jones

26

NumPy không cung cấp chức năng chung để tính toán các dẫn xuất. Tuy nhiên, nó có thể xử lý trường hợp đặc biệt đơn giản của đa thức:

>>> p = numpy.poly1d([1, 0, 1])
>>> print p
   2
1 x + 1
>>> q = p.deriv()
>>> print q
2 x
>>> q(5)
10

Nếu bạn muốn tính đạo hàm bằng số, bạn có thể sử dụng thương số chênh lệch trung tâm cho phần lớn các ứng dụng. Đối với đạo hàm tại một điểm duy nhất, công thức sẽ giống như

x = 5.0
eps = numpy.sqrt(numpy.finfo(float).eps) * (1.0 + x)
print (p(x + eps) - p(x - eps)) / (2.0 * eps * x)

nếu bạn có một mảng xabscissae với một mảng ygiá trị hàm tương ứng , bạn có thể tính các giá trị gần đúng của các đạo hàm với

numpy.diff(y) / numpy.diff(x)

2
'Tính toán đạo hàm số cho trường hợp tổng quát hơn thì dễ' - Tôi xin phép khác, tính toán đạo hàm số cho trường hợp tổng quát khá khó. Bạn chỉ cần chọn các chức năng hoạt động tốt.
hiệu suất cao vào

2 có nghĩa là gì sau >>> in p ?? (trên dòng thứ 2)
DrStrangeLove

@DrStrangeLove: Đó là số mũ. Nó có nghĩa là để mô phỏng ký hiệu toán học.
Sven Marnach

@SvenMarnach có phải là số mũ tối đa không ?? hay cái gì?? Tại sao nó nghĩ rằng số mũ là 2 ?? Chúng tôi chỉ nhập các hệ số ...
DrStrangeLove

2
@DrStrangeLove: Đầu ra phải được đọc là 1 * x**2 + 1. Họ đặt 2ở dòng trên vì nó là số mũ. Nhìn nó từ xa.
Sven Marnach

14

Giả sử bạn muốn sử dụng numpy, bạn có thể tính toán số học đạo hàm của một hàm tại bất kỳ thời điểm nào bằng cách sử dụng định nghĩa chặt chẽ :

def d_fun(x):
    h = 1e-5 #in theory h is an infinitesimal
    return (fun(x+h)-fun(x))/h

Bạn cũng có thể sử dụng đạo hàm Đối xứng để có kết quả tốt hơn:

def d_fun(x):
    h = 1e-5
    return (fun(x+h)-fun(x-h))/(2*h)

Sử dụng ví dụ của bạn, mã đầy đủ sẽ trông giống như sau:

def fun(x):
    return x**2 + 1

def d_fun(x):
    h = 1e-5
    return (fun(x+h)-fun(x-h))/(2*h)

Bây giờ, bạn có thể tìm bằng số về đạo hàm tại x=5:

In [1]: d_fun(5)
Out[1]: 9.999999999621423

8

Tôi sẽ ném một phương pháp khác lên đống ...

scipy.interpolateNhiều splines nội suy có khả năng cung cấp các dẫn xuất. Vì vậy, bằng cách sử dụng một spline tuyến tính ( k=1), đạo hàm của spline (sử dụng derivative()phương pháp) sẽ tương đương với một hiệu số chuyển tiếp. Tôi không hoàn toàn chắc chắn, nhưng tôi tin rằng việc sử dụng đạo hàm spline lập phương sẽ tương tự như một đạo hàm chênh lệch tâm vì nó sử dụng các giá trị từ trước và sau để tạo spline lập phương.

from scipy.interpolate import InterpolatedUnivariateSpline

# Get a function that evaluates the linear spline at any x
f = InterpolatedUnivariateSpline(x, y, k=1)

# Get a function that evaluates the derivative of the linear spline at any x
dfdx = f.derivative()

# Evaluate the derivative dydx at each x location...
dydx = dfdx(x)

vừa thử điều này, tôi tiếp tục gặp lỗi từ hàm này AxisError: axis -1 nằm ngoài giới hạn cho mảng thứ nguyên 0 và tôi cũng không thấy bất kỳ câu trả lời nào cho vấn đề này trên cộng đồng, bất kỳ trợ giúp nào?
Ayan Mitra

Đăng vấn đề của bạn dưới dạng một câu hỏi mới và liên kết đến nó ở đây. Có thể cần cung cấp một ví dụ khiến lỗi của bạn xảy ra. Các lỗi tôi gặp phải với các hàm interp thường là do dữ liệu không được định dạng tốt khi đi vào - như giá trị lặp lại, số thứ nguyên sai, một trong các mảng vô tình bị trống, dữ liệu không được sắp xếp theo x hoặc khi được sắp xếp không phải là hàm hợp lệ, v.v. Có thể scipy đang gọi sai numpy, nhưng rất khó xảy ra. Kiểm tra x.shape và y.shape. Xem np.interp () có hoạt động không - nó có thể cung cấp một lỗi hữu ích hơn nếu không.
flanfreak7

5

Để tính toán độ dốc, cộng đồng học máy sử dụng Autograd:

" Tính toán hiệu quả các dẫn xuất của mã numpy. "

Để cài đặt:

pip install autograd

Đây là một ví dụ:

import autograd.numpy as np
from autograd import grad

def fct(x):
    y = x**2+1
    return y

grad_fct = grad(fct)
print(grad_fct(1.0))

Nó cũng có thể tính toán độ dốc của các hàm phức tạp, ví dụ như các hàm đa biến.


Xin chào, chức năng này có thể được sử dụng để phân biệt giữa hai cột dữ liệu bằng cách cung cấp độ dài bước không? cảm ơn
Ayan Mitra

3

Tùy thuộc vào mức độ chính xác mà bạn yêu cầu, bạn có thể tự giải quyết bằng cách sử dụng bằng chứng phân biệt đơn giản:

>>> (((5 + 0.1) ** 2 + 1) - ((5) ** 2 + 1)) / 0.1
10.09999999999998
>>> (((5 + 0.01) ** 2 + 1) - ((5) ** 2 + 1)) / 0.01
10.009999999999764
>>> (((5 + 0.0000000001) ** 2 + 1) - ((5) ** 2 + 1)) / 0.0000000001
10.00000082740371

chúng ta không thể thực sự hiểu giới hạn của gradient, nhưng nó khá thú vị. Bạn phải cẩn thận mặc dù vì

>>> (((5+0.0000000000000001)**2+1)-((5)**2+1))/0.0000000000000001
0.0

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.