我上第一节数值分析课时,老师着重解释着数学原理,对于如何实现这些算法只是留给我们一些伪代码。这些伪代码由基础运算和各种for loop
组成。我想一段好的数值分析代码有无数种替代for loop
的方法,更简洁和易读。
Sum
求和符号频繁的出现在各种公式里面。比如 Composite Simpson Rule:
我之前看到求和符号的第一反应是这儿又得用 for loop
了。例如
可能会用以下的代码来计算。
sum=0
for i in range(1,n//2+1):
sum = sum+f(a+(2*i-1)*h)
sum
这是一个有点冗长,不清楚的写法。
Map
我们可以用np.sum
和map
函数来实现。
import numpy as np
np.sum(np.array(list(map(lambda i:f(a+(2*i-1)*h),np.arange(1,n//2+1)))))
瞬间把之前的几行代码压缩成了一行。这样写的坏处是括号比较多,在没有括号高亮的情况下容易出现漏括号或者多括号的情况。
Vectorize
这个方法全靠 Numpy。
import numpy as np
i = np.arange(1,n//2+1)
sum1 = lambda i: f(a+(2*i-1)*h)
vfunc = np.vectorize(sum1)
np.sum(vfunc(i))
这个思路和Map
的思路类似,但优势是创建了一个可以复用的 Vectorize Function,可以接受数组的输入。
Another For Loop
这个其实和 ·for loop
没什么区别,知识短了一点。
import numpy as np
np.sum([f(a+(2*i-1)*h) for i in np.arange(1,n//2+1) ])
这个方法会比较灵活。在面对多个参数的时候会比较好用。比如有一个函数 f(a,b,c,d) ,只有 c 这个参数需要变化,a,b,d 都是不要变化的。我们可以写这样写:
import numpy as np
[f(a,b,c,d) for c in np.arange(n)]
矩阵点乘
这里我们用一个简单一点的例子。我们需要计算
。这个的本质是 a 和 b 两个矩阵的点乘。
a=[...]
b=[...]
np.dot(a,b)
快速生成一个矩阵
这个很简单。例如生成一个5*5矩阵。
import numpy as np
np.zeros((5, 5))
Table
Tabulate
print(tabulate([["Name","Age"],["Alice",24],["Bob",19]],headers="firstrow"))
# Name Age
# ------ -----
# Alice 24
# Bob 19
print(tabulate({"Name": ["Alice", "Bob"],
"Age": [24, 19]}, headers="keys"))
# Age Name
# ----- ------
# 24 Alice
# 19 Bob
Plotly
import plotly.graph_objects as go
fig = go.Figure(data=[go.Table(header=dict(values=['A Scores', 'B Scores']),
cells=dict(values=[[100, 90, 80, 90], [95, 85, 75, 95]]))
])
fig.show()
Plot
我每次都记不住怎么画图。
matplotlib
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(9,6))
ax.loglog(hs,composite_trapezoid_rule_error_func1,'bo-',label='CTR ERROR',lw=2)
ax.loglog(hs,np.power(hs,2),'ro-',label='err(h) = h^2',lw=2)
ax.set_title("Error in CTR approximation",fontsize=22)
ax.legend(fontsize=15)
ax.set_xlabel('h',fontsize=22)
ax.set_ylabel('err(h)',fontsize=22)
ax.xaxis.set_tick_params(labelsize=15)
ax.yaxis.set_tick_params(labelsize=15)
题图来自: Lorena Lane