前導:程式與數值計算關係
1.統計分析 vs. 機器學習
統計:找出真相、因果推理
機器:解決問題、預測結果
2.數學:解決問題的方法
<線性>
(1)如何解決問題-方程式
(2)固定&變動資訊-截距&斜率
(3)瞬間變化量-微分
(4)趨近值-極限
<非線性>
(5)敘述統計:聚集、離散程度
(6)推論統計:資料無法探索
(7)機率、分配
(8)母體、抽樣、檢定、標準差
Google Colab
- 環境:Ubuntu + Python3.7
- 套件:每次執行都得重新安裝
- 檔案:執行完就會刪除
- 免費版本不能於背景執行
一、線性方程式:求斜率&截距
matplotlib.pyplot - Documentation
01. Set (in Google Colab)
# !pip install matplotlib
# !pip install numpy
# ! 表示轉移至Linux環境下達指令 (離開python環境)
import matplotlib.pyplot as plt
import numpy as np
x = [1,2,3,4,5,6,7]
y = [1,3,3,12,5,7,9]
plt.plot(x,y,'--') # x軸、y軸、虛線表示
plt.grid() # 增加格線
plt.show() # 顯示圖形
02. 轉換成線性方程式(斜率、截距)
# 令有一次方程式: y = slope * x + intercept
# np.polyfit(x,y,N): 可將現資料(x,y)調整找出N次方程式, 回傳list
slope, intercept = np.polyfit(x,y,1)
print(slope)
print(intercept)
# 若拆解成二次方程式 (y = a * x ** 2 + b * x + c)
# 等號左邊可以得幾個值,視等號右邊會拆成幾個變數
a, b, c = np.polyfit(x,y,2)
print(data)
# 以一次方程式為例,列出每一個x值所對應y值(list)
y1 = [slope * i + intercept for i in x]
plt.plot(x,y,'--')
plt.plot(x,y1,'r') #red
plt.grid()
plt.show()
練習一、經濟部1994-2004年經濟成長率
x = np.arange(1994,2005,1) # 1994-2005,1年1格
y = [7.11,6.42,6.10,6.37,4.33,5.32,5.78,-2.22,3.94,3.33,5.71]
# 以 polyfit 求一次方程式,以進行預測
slope, intercept = np.polyfit(x,y,1)
print(f"斜率: {slope}")
print(f"截距: {intercept}")
# 產生list: 每一個x所對應的y值
y1 = [slope * i + intercept for i in x]
plt.plot(x,y,'--')
plt.plot(x,y1,'r') #red
plt.grid()
plt.show()
# 試求二次方程式 (y = a * x ** 2 + b * x + c)
a, b, c = np.polyfit(x,y,2)
y1 = [a * i ** 2 + b * i + c for i in x]
plt.plot(x,y,'--')
plt.plot(x,y1,'r') #red
plt.grid()
plt.show()
練習二、銷售業績計算(CSV)
- 若數值凌亂不一定可以推出線性方程式 => 以最近鄰概念進行推估
- 建議最高至三元(三欄位)即可,可以3D圖表呈現
- 連結google drive內檔案
from google.colab import drive
drive.mount('/content/drive', force_remount=True)
# force_remount=True 強制安裝驅動器,避免中斷情形
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.read_csv("/content/drive/MyDrive/colab/Advertising.csv")
x = df['Newspaper']
y = df['Sales']
plt.scatter(x,y) # 使用散佈圖
# plt.plot(x,y) # 使用曲線圖
plt.show()
# 加入polyfit找出資料中的線性關係
a,b,c = np.polyfit(x,y,2)
y1 = [a * i ** 2 + b * i + c for i in x]
plt.scatter(x, y)
plt.plot(x, y1, "r")
plt.show()
資料過於零散,無法得出有效表示關係之方程式
二、解方程式
- 需先以
物件 = sympy.Symbol('符號')
定義函式內物件 - f(x) = 0 或 聯立方程式 => 求變數解
- 以
sympy.solve([input],[output])
求解(回傳dictionary)
- 以
- 線性方程式 f(x) = ax+by+c => 求每一變數對應值
- 以
sympy.lambdify((x, y), function)
或sympy.Lambda((x, y), funciton)
建立物件計算
- 以
- 二次函數極值與圖形
- 以
numpy.arange
限定範圍求var.argmin()
或var.argmax()
- 以
matplotlib.pyplot.scatter(x,y)
散佈圖點出極值位置 - 亦可微分(
.diff
)求解(.solve
)並帶回原式(.lambdify
)
- 以
二元一次聯立方程式
# eg 1.
import sympy as sp
import numpy as np
x = sp.Symbol('x')
y = sp.Symbol('y')
f1 = 2 * x + 3 * y - 23
f2 = x + 4 * y - 24
print(sp.solve([f1, f2], [x, y]))
> {x: 4, y: 5}
# eg 2.
# 有草莓(50元)、巧克力(30元)兩種冰淇淋
s = sp.Symbol('s')
c = sp.Symbol('c')
# 總數量 = 20個
f1 = s + c - 20
# 總金額 = 800元
f2 = 50 * s + 30 * c - 800
# f1, f2 表示兩個答案為零的方程式
answer = sp.solve([f1, f2], [s, c])
print(answer)
print(answer.__class__) # 回傳資料的屬性
print(type(answer)) # 回傳資料的型態
print("草莓冰淇淋份數: ", answer[s])
print("巧克力冰淇淋份數: ", answer[c])
> {s: 10, c: 10}
> <class 'dict'>
> <class 'dict'>
> 草莓冰淇淋份數: 10
> 巧克力冰淇淋份數: 10
線性方程式求解 lambdify vs. Lambda
from sympy import lambdify, Symbol, Lambda
import numpy as np
'''
lambdify vs. Lambda
ddx = lambdify(自變數, 方程式)
answer = ddx(自變數代入數值)
func = Lambda(自變數, 方程式)
answer = func(自變數代入數值)
'''
print("\n\n----- 若x = -1,求一階導數的結果 -----")
x = sp.Symbol('x')
y1 = 2 * np.power(x,4) - 3 * np.power(x,2) + 2 * x - 20
print("\n原方程式: ", y1)
y2 = y1.diff(x)
print("一階函式: ", y2)
y3 = 8 * (-1) ** 3 - 6 * (-1) + 2
print("\n【法1】直接代入: ",y3)
ddx = lambdify(x, y2)
print("\n【法2】使用lambdify: ",ddx(-1))
func = sp.Lambda(x, y2)
print("\n【法3】使用Lambda: ",func(-1))
print("\n\n----- 使 x = -5 ~ 5,判斷函式圖形 -----")
ddx = lambdify(x, y1)
print("\n【法1】使用lambdify:", ddx(np.arange(-5, 5, 1)))
func = Lambda(x, y1)
# print(func(np.arange(-5, 5, 1))) => error
print("\n【法2】使用Lambda: errer - 無法代入list")
print("\n\n----- 若x = 3, y = 7,二元方程式求解 -----")
x = sp.Symbol('x')
y = sp.Symbol('y')
f = x ** 2 - 2 * y + 4 * x -3
print("\n令二元方程式: ", f)
ddx = lambdify((x, y), f)
print("\n【法1】使用lambdify: ", ddx(3, 7))
func = Lambda((x, y), f)
print("\n【法2】使用Lambda: ", func(3, 7))
print("\n**lambdify物件: ", ddx.__class__)
print("**Lambda物件: ", func.__class__)
二次函數-極值與圖形
import sympy as sp
print("\n---- 令x為正負10以內整數,求極值 ----")
x = np.arange(-10, 11, 1)
y = -3 * x ** 2 + 20 * x + 3
y_max = np.max(y)
x_max = x[y.argmax()]
print("\n求圖形最高點: ", x_max, ",", y_max)
print("\n---- 繪製二次函數圖形 (放大、並標示最大值) ----")
# 放大圖表
plt.figure(figsize=(8, 5))
plt.plot(x, y)
# 以散佈圖方式點出最大值
plt.scatter(x_max, y_max, c='r')
plt.grid()
plt.show()
print("\n---- 以微分求極值 ----")
x = sp.Symbol("x")
y = -3 * x ** 2 + 20 * x + 3
y_diff = y.diff(x)
x_max = sp.solve([y_diff],[x])[x]
ddf = sp.lambdify(x, y)
y_max = ddf(x_max)
print("\n求圖形最高點: ", x_max, ",", y_max)
三、微分與極值
- 一次函數
f'(x) = f.diff(x)
- 極限函式
sympy.limit(函式, 自變數,趨近值)
- 以
sp.oo
表示無限大
# ---------- 微分 ---------- #
# 意義:求瞬間變化量
x = sp.Symbol('x')
y = np.power(x,5)+ 2*np.power(x,4)+ 3*np.power(x,3)+ 4*np.power(x,2)+ 5*x+ 6
y2 = y.diff(x) # 對y做x的微分
print(y2)
> 5*x**4 + 8*x**3 + 9*x**2 + 8*x + 5
# ---------- 極限 ---------- #
# 意義:求 x = ? 會使 函式 趨近於 趨近值
x = sp.Symbol('x')
f3 = sp.limit((x**2+2*x-3)/(x-1),x,sp.oo)
print(f3)
> oo