Saya harus membuat polinomial Lagrange dengan Python untuk proyek yang saya lakukan. Saya sedang melakukan gaya barycentric untuk menghindari menggunakan for-loop eksplisit sebagai lawan dari gaya perbedaan perbedaan Newton. Masalah yang saya miliki adalah bahwa saya perlu menangkap pembagian dengan nol, tetapi Python (atau mungkin numpy) hanya menjadikannya peringatan, bukan pengecualian normal.
Jadi, apa yang perlu saya ketahui bagaimana melakukannya adalah menangkap peringatan ini seolah-olah itu pengecualian. Pertanyaan terkait dengan ini saya temukan di situs ini dijawab tidak seperti yang saya butuhkan. Ini kode saya:
import numpy as np
import matplotlib.pyplot as plt
import warnings
class Lagrange:
def __init__(self, xPts, yPts):
self.xPts = np.array(xPts)
self.yPts = np.array(yPts)
self.degree = len(xPts)-1
self.weights = np.array([np.product([x_j - x_i for x_j in xPts if x_j != x_i]) for x_i in xPts])
def __call__(self, x):
warnings.filterwarnings("error")
try:
bigNumerator = np.product(x - self.xPts)
numerators = np.array([bigNumerator/(x - x_j) for x_j in self.xPts])
return sum(numerators/self.weights*self.yPts)
except Exception, e: # Catch division by 0. Only possible in 'numerators' array
return yPts[np.where(xPts == x)[0][0]]
L = Lagrange([-1,0,1],[1,0,1]) # Creates quadratic poly L(x) = x^2
L(1) # This should catch an error, then return 1.
Ketika kode ini dieksekusi, output yang saya dapatkan adalah:
Warning: divide by zero encountered in int_scalars
Itu peringatan yang ingin saya tangkap. Itu harus terjadi di dalam daftar pemahaman.
Warning: ...
? Mencoba hal-hal seperti yangnp.array([1])/0
saya dapatkanRuntimeWarning: ...
sebagai output.Jawaban:
Tampaknya konfigurasi Anda menggunakan
print
opsi untuknumpy.seterr
:Ini berarti bahwa peringatan yang Anda lihat bukan peringatan yang sebenarnya, tetapi itu hanya beberapa karakter yang dicetak
stdout
(lihat dokumentasi untukseterr
). Jika Anda ingin menangkapnya, Anda dapat:numpy.seterr(all='raise')
yang secara langsung akan meningkatkan pengecualian. Namun ini mengubah perilaku semua operasi, jadi itu adalah perubahan perilaku yang cukup besar.numpy.seterr(all='warn')
, yang akan mengubah peringatan tercetak menjadi peringatan nyata dan Anda akan dapat menggunakan solusi di atas untuk melokalisasi perubahan perilaku ini.Setelah Anda benar-benar memiliki peringatan, Anda dapat menggunakan
warnings
modul untuk mengontrol bagaimana peringatan harus diperlakukan:Baca dengan seksama dokumentasi
filterwarnings
karena memungkinkan Anda untuk memfilter hanya peringatan yang Anda inginkan dan memiliki opsi lain. Saya juga akan mempertimbangkan untuk melihatcatch_warnings
mana yang merupakan manajer konteks yang secara otomatis me-resetfilterwarnings
fungsi asli :sumber
RuntimeWarning
. Diperbarui jawabannya.RuntimeWarning
dinaikkan. Masalahnya mungkin bahwa konfigurasi numpy Anda menggunakanprint
opsi, yang hanya mencetak peringatan tetapi itu bukan peringatan nyata yang ditangani olehwarnings
modul ... Jika ini adalah kasus Anda dapat mencoba menggunakannumpy.seterr(all='warn')
dan coba lagi.numpy
, Anda tidak dapat menggunakannumpy.seterr(all='error')
,error
harusraise
.Untuk menambahkan sedikit pada jawaban @ Bakuriu:
Jika Anda sudah tahu di mana peringatan itu mungkin terjadi maka sering kali lebih baik menggunakan
numpy.errstate
manajer konteks, daripadanumpy.seterr
yang memperlakukan semua peringatan berikutnya dari jenis yang sama sama terlepas di mana mereka muncul dalam kode Anda:Edit:
Dalam contoh asli saya
a = np.r_[0]
, tetapi ternyata ada perubahan dalam perilaku numpy sehingga pembagian-by-nol ditangani secara berbeda dalam kasus di mana pembilangnya adalah semua-nol. Misalnya, dalam numpy 1.16.4:Pesan peringatan yang sesuai juga berbeda:
1. / 0.
dicatat sebagaiRuntimeWarning: divide by zero encountered in true_divide
, sedangkan0. / 0.
dicatat sebagaiRuntimeWarning: invalid value encountered in true_divide
. Saya tidak yakin mengapa tepatnya perubahan ini dibuat, tetapi saya menduga itu ada hubungannya dengan fakta bahwa hasil0. / 0.
tidak dapat diwakili sebagai angka (numpy mengembalikan NaN dalam kasus ini) sedangkan1. / 0.
dan-1. / 0.
return + Inf dan -Inf masing-masing , sesuai standar IEE 754.Jika Anda ingin menangkap kedua jenis kesalahan, Anda selalu dapat lulus
np.errstate(divide='raise', invalid='raise')
, atauall='raise'
jika Anda ingin meningkatkan pengecualian pada segala jenis kesalahan floating point.sumber
FloatingPointError
, bukanZeroDivisionError
.Python 3.6.3
dengannumpy==1.16.3
. Bisakah Anda memperbaruinya?Untuk menguraikan jawaban @ Bakuriu di atas, saya menemukan bahwa ini memungkinkan saya menangkap peringatan runtime dengan cara yang mirip dengan cara saya menangkap peringatan kesalahan, mencetak peringatan dengan baik:
Anda mungkin dapat bermain-main dengan penempatan penempatan peringatan.catch_warnings () tergantung pada seberapa besar payung yang ingin Anda buat dengan kesalahan menangkap dengan cara ini.
sumber
Hapus warnings.filterwarnings dan tambahkan:
sumber