一、概觀
創(chuàng)新互聯(lián)公司主要業(yè)務有網(wǎng)站營銷策劃、成都網(wǎng)站設計、成都網(wǎng)站制作、微信公眾號開發(fā)、重慶小程序開發(fā)、HTML5建站、程序開發(fā)等業(yè)務。一次合作終身朋友,是我們奉行的宗旨;我們不僅僅把客戶當客戶,還把客戶視為我們的合作伙伴,在開展業(yè)務的過程中,公司還積累了豐富的行業(yè)經(jīng)驗、成都全網(wǎng)營銷推廣資源和合作伙伴關系資源,并逐漸建立起規(guī)范的客戶服務和保障體系。
scipy中的optimize子包中提供了常用的最優(yōu)化算法函數(shù)實現(xiàn)。我們可以直接調(diào)用這些函數(shù)完成我們的優(yōu)化問題。optimize中函數(shù)最典型的特點就是能夠從函數(shù)名稱上看出是使用了什么算法。下面optimize包中函數(shù)的概覽:
1.非線性最優(yōu)化
fmin -- 簡單Nelder-Mead算法
fmin_powell -- 改進型Powell法
fmin_bfgs -- 擬Newton法
fmin_cg -- 非線性共軛梯度法
fmin_ncg -- 線性搜索Newton共軛梯度法
leastsq -- 最小二乘
2.有約束的多元函數(shù)問題
fmin_l_bfgs_b ---使用L-BFGS-B算法
fmin_tnc ---梯度信息
fmin_cobyla ---線性逼近
fmin_slsqp ---序列最小二乘法
nnls ---解|| Ax - b ||_2 for x=0
3.全局優(yōu)化
anneal ---模擬退火算法
brute --強力法
4.標量函數(shù)
fminbound
brent
golden
bracket
5.擬合
curve_fit-- 使用非線性最小二乘法擬合
6.標量函數(shù)求根
brentq ---classic Brent (1973)
brenth ---A variation on the classic Brent(1980)ridder ---Ridder是提出這個算法的人名
bisect ---二分法
newton ---牛頓法
fixed_point
7.多維函數(shù)求根
fsolve ---通用
broyden1 ---Broyden’s first Jacobian approximation.
broyden2 ---Broyden’s second Jacobian approximationnewton_krylov ---Krylov approximation for inverse Jacobiananderson ---extended Anderson mixing
excitingmixing ---tuned diagonal Jacobian approximationlinearmixing ---scalar Jacobian approximationdiagbroyden ---diagonal Broyden Jacobian approximation8.實用函數(shù)
line_search ---找到滿足強Wolfe的alpha值
check_grad ---通過和前向有限差分逼近比較檢查梯度函數(shù)的正確性二、實戰(zhàn)非線性最優(yōu)化
fmin完整的調(diào)用形式是:
fmin(func, x0, args=(), xtol=0.0001, ftol=0.0001, maxiter=None, maxfun=None, full_output=0, disp=1, retall=0, callback=None)不過我們最常使用的就是前兩個參數(shù)。一個描述優(yōu)化問題的函數(shù)以及初值。后面的那些參數(shù)我們也很容易理解。如果您能用到,請自己研究。下面研究一個最簡單的問題,來感受這個函數(shù)的使用方法:f(x)=x**2-4*x+8,我們知道,這個函數(shù)的最小值是4,在x=2的時候取到。
from scipy.optimize import fmin #引入優(yōu)化包def myfunc(x):
return x**2-4*x+8 #定義函數(shù)
x0 = [1.3] #猜一個初值
xopt = fmin(myfunc, x0) #求解
print xopt #打印結(jié)果
運行之后,給出的結(jié)果是:
Optimization terminated successfully.
Current function value: 4.000000
Iterations: 16
Function evaluations: 32
[ 2.00001953]
程序準確的計算得出了最小值,不過最小值點并不是嚴格的2,這應該是由二進制機器編碼誤差造成的。
除了fmin_ncg必須提供梯度信息外,其他幾個函數(shù)的調(diào)用大同小異,完全類似。我們不妨做一個對比:
from scipy.optimize import fmin,fmin_powell,fmin_bfgs,fmin_cgdef myfunc(x):
return x**2-4*x+8
x0 = [1.3]
xopt1 = fmin(myfunc, x0)
print xopt1
xopt2 = fmin_powell(myfunc, x0)
print xopt2
xopt3 = fmin_bfgs(myfunc, x0)
print xopt3
xopt4 = fmin_cg(myfunc,x0)
print xopt4
給出的結(jié)果是:
Optimization terminated successfully.
Current function value: 4.000000
Iterations: 16
Function evaluations: 32
[ 2.00001953]
Optimization terminated successfully.
Current function value: 4.000000
Iterations: 2
Function evaluations: 53
1.99999999997
Optimization terminated successfully.
Current function value: 4.000000
Iterations: 2
Function evaluations: 12
Gradient evaluations: 4
[ 2.00000001]
Optimization terminated successfully.
Current function value: 4.000000
Iterations: 2
Function evaluations: 15
Gradient evaluations: 5
[ 2.]
我們可以根據(jù)給出的消息直觀的判斷算法的執(zhí)行情況。每一種算法數(shù)學上的問題,請自己看書學習。個人感覺,如果不是純研究數(shù)學的工作,沒必要搞清楚那些推導以及定理云云。不過,必須了解每一種算法的優(yōu)劣以及能力所及。在使用的時候,不妨多種算法都使用一下,看看效果分別如何,同時,還可以互相印證算法失效的問題。
在from scipy.optimize import fmin之后,就可以使用help(fmin)來查看fmin的幫助信息了。幫助信息中沒有例子,但是給出了每一個參數(shù)的含義說明,這是調(diào)用函數(shù)時候的最有價值參考。
有源碼研究癖好的,或者當你需要改進這些已經(jīng)實現(xiàn)的算法的時候,可能需要查看optimize中的每種算法的源代碼。在這里:https:/ / github. com/scipy/scipy/blob/master/scipy/optimize/optimize.py聰明的你肯定發(fā)現(xiàn)了,順著這個鏈接往上一級、再往上一級,你會找到scipy的幾乎所有源碼!
題目:有一個升序的數(shù)組,數(shù)組中可能有正數(shù)、負數(shù)或者0,求數(shù)組中元素的絕對值最小的數(shù)。例如,數(shù)組[-10, -5, -2, 7, 15, 50],該數(shù)組中絕對值最小的數(shù)是-2。
分析:二分法。該題可分為以下三種情況:
(1)如果數(shù)組第一個元素為非負數(shù),那么minNum = arr[0]
(2)如果數(shù)組最后一個值為負數(shù),那么minNum = arr[-1]。
(3)如果數(shù)組中既有正數(shù)又有負數(shù),首先找到正數(shù)與負數(shù)的分界點,如果分界點恰好為0,那么0為最小值。否則通過比較分界點左右的正數(shù)與負數(shù)的絕對值來確定最小數(shù)。
如何查找正數(shù)與負數(shù)的分界點呢?采用二分法,主要思路:取數(shù)組中間位置的值a[mid],并將它與0值比較,比較結(jié)果分為如下三種情況:
(1)如果a[mid] == 0,那么這個數(shù)就是絕對值最小的數(shù)。
(2)如果a[mid] 0,a[mid - 1] 0,那么通過比較a[mid]與a[mid - 1]的絕對值就可以找到數(shù)組中絕對值最小的數(shù);如果a[mid - 1] == 0, 那么a[mid - 1]就是要找的數(shù);否則接著在數(shù)組的左半部分查找。
(3)如果a[mid] 0,a[mid + 1] 0,那么通過比較a[mid]與a[mid +1]的絕對值就可以找到數(shù)組中絕對值最小的數(shù);如果a[mid + 1] == 0, 那么a[mid + 1]就是要找的數(shù);否則接著在數(shù)組的右半部分查找。
code:
def findMinNum(arr):
if arr is None or len(arr) = 0:
? ? return
# [1] 數(shù)組中沒有負數(shù)
if arr[0] = 0:
? ? return arr[0]
# [2] 數(shù)組中沒有正數(shù)
if arr[-1] = 0:
? ? return arr[-1]
# [3] 數(shù)組中既有正數(shù)又又負數(shù)
mid = None
absMin = None
begin = 0
end = len(arr) - 1
while begin end:
? ? mid = begin + (end - begin) 1
? ? # 如果arr[mid] == 0,則是絕對值最小的數(shù)
? ? if arr[mid] == 0:
? ? ? ? return 0
? ? # 如果大于0, 正負數(shù)的分界點在左側(cè)
? ? elif arr[mid] 0:
? ? ? ? # 繼續(xù)在數(shù)組的左半部分查找
? ? ? ? if arr[mid - 1] 0:
? ? ? ? ? ? end = mid - 1
? ? ? ? elif arr[mid - 1] == 0:
? ? ? ? ? ? return 0
? ? ? ? # 找到正負數(shù)的分界點
? ? ? ? else:
? ? ? ? ? ? break? # 如果小于0, 在數(shù)組右半部分查找
? ? else:
? ? ? ? # 在數(shù)組的右半部分繼續(xù)查找
? ? ? ? if arr[mid + 1] 0:
? ? ? ? ? ? begin = mid + 1
? ? ? ? elif arr[mid + 1] == 0:
? ? ? ? ? ? return 0
? ? ? ? else:
? ? ? ? ? ? break
# 獲取正負數(shù)分界點處絕對值最小的值
if (arr[mid] 0):
? ? if arr[mid] abs(arr[mid - 1]):
? ? ? ? absMin = arr[mid]
? ? else:
? ? ? ? absMin = arr[mid - 1]
else:
? ? if abs(arr[mid]) abs(arr[mid + 1]):
? ? ? ? absMin = arr[mid]
? ? else:
? ? ? ? absMin = arr[mid + 1]
return absMin
if __name__ == "__main__":
arr = [-10, -5, -2, 7, 15, 50]
print(findMinNum(arr))
代碼有兩個地方有問題
1:19行的return縮進有問題,19行的return不應該出現(xiàn)在一個非方法的地方
2:?代碼有可能出現(xiàn)死循環(huán),在我輸入a:10,?b:10,?c:10,?d:10的時候出現(xiàn)死循環(huán),請檢查代碼邏輯
我已經(jīng)調(diào)整好了
def?f(x):
s=(a*x)**3+(b*x)**2+(c*x)+d
return?s
a=int(input("a"))
b=int(input("b"))
c=int(input("c"))
d=int(input("d"))
mid?=?0
for?i?in?range(-100,100,1):
x1=int(i)
x2=int(i+1)
if?f(x1)*f(x2)0:
lo,hi=x1,x2
while?hi-lo0.01:
mid=(lo+hi)/2
if?f(lo)*f(mid)0:
hi=mid
else:
lo=mid
else:
pass
print?mid
import math
def erfenfa(function, a, b): #定義函數(shù),利用二分法求方程的根,function為具體方程,a,b為根的取值范圍
start = a
end = b
if function(a) == 0:?
return a
elif function(b) == 0:
return b
elif function(a) * function(b) 0:?
print("couldn't find root in [a,b]")
return
else:
mid = (start + end) / 2
while abs(start - mid) 0.0000001:?
if function(mid) == 0:
return mid
elif function(mid) * function(start) 0:
end = mid
else:
start = mid
mid = (start + end) / 2
return mid
def f(x):#定義構(gòu)造方程式函數(shù)
return math.pow(x, 5) -15*math.pow(x, 4) +85*math.pow(x, 3)-225*pow(x,2)+274*x - 121
print(round(erfenfa(f, 1.5, 2.4),6))
def erfen(low,high):
while low high:
mid=(low+high)/2
if f(low)*f(mid)0:
high=mid
elif f(mid)*f(high )0:
low=mid
return mid
這個函數(shù)沒有結(jié)束 檢查一下如何設置退出條件
首先二分法肯定需要一個“不斷”二分的過程, 你的代碼里面連一個循環(huán)都沒有,肯定是不對的吧?
其次按照你的代碼的思路,如果當前估算值guess的平法比x大,那就往0那邊靠,否則就往1那邊靠,這個好像也不對吧?
二分法的實現(xiàn)方法應該是,在區(qū)間[left, right]里面找x的開方,令估算值為guess等于區(qū)間的中點,如果guess比實際的大,那就把區(qū)間縮小一半,令到右端點移動到中點,如果guess比實際的小,也是將區(qū)間縮小一半,但是是令左端點移動到中點。這樣每次縮小一半的區(qū)間,直到區(qū)間的長度非常非常小,那就認為區(qū)間的兩個端點是相等的了,這個時候就得到了答案。
import?math
def?main():
x?=?input('x=')
n?=?0
if?x?=?1?and?x?=?0:
left?=?0.
right?=?1.
while?right?-?left?=?0.0000001:
guess?=?(left?+?right)?/?2.
if?guess?**?2?-?x?=?0.0000001:
right?=?guess
else:
left?=?guess
#return?guess
print?'sqrt(x)?is',?left
else:
print?'x?should?be?in?[0,1]'
if?__name__?==?'__main__':
main()
我按照你的思路又寫了另外一種方法:
def?second():
x?=?input('x=')
n?=?0
if?x?=?1?and?x?=?0:
movelen?=?(1?+?0)?/?4.
guess?=?(1?+?0)?/?2.
while?abs(guess?**?2?-?x)?=?0.0000001:
if?(guess?**?2?-?x)?=?0.0000001:
guess?=?guess?-?movelen
else:
guess?=?guess?+?movelen
movelen?=?movelen?/?2.
print?'sqrt(x)?is',?guess
else:
print?'x?should?be?in?[0,1]'