今天我們會簡單介紹 Python 在算數學的時候, 可以用到的一些基本工具。做這個的目的, 除了介紹基本工具, 更重要的是希望大家知道, 「你一定要去寫有意思的程式, 你才有興趣寫下去。」
也就是, 「你要覺得好玩才可以。」也許是我們同學太優秀, 所以似乎不太會找好玩的問題。
另一方面, 如果我們要學的東西就是, 嗯, 什麼貝式統計啦, 假設檢定啦, information theory 啦, 或其他任何有點深奧生硬的主題, 要怎麼辦呢? 一個很好的方法, 就是用 Python 寫程式來幫你學習!
很能代表這樣精神的, 就是 Allen Downey 教授, 他學什麼都寫成程式。他以前是寫 Java 的, 有本很出名的書叫 "How To Think Like a Computer Scientist", 第一版用的是 Java。之後有人覺得這本書太有意思, 和他合寫 Python 版, 然後他的主力程式語言就變成 Python 了!
另一個很好的例子是 Mosky, 她是台科大資料系出身, 近來非常認真的唸數學和統計學, 她的
【Hypothesis Testing with Python】
就是很好的「用電腦學習」的範例。
數據分析最重要的概念, 大概是「不到最後關頭, 絕不輕言使用迴圈」。
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
有一班同學成績是這樣的:
grades = [35, 74, 43, 66, 87, 55, 71, 65]
老師想要每位同學成績都是乘 1.1 倍!
grades = [35, 74, 43, 66, 87, 55, 71, 65]
curved = []
for g in grades:
curved.append(g*1.1)
curved
[38.5, 81.4, 47.300000000000004, 72.60000000000001, 95.7, 60.50000000000001, 78.10000000000001, 71.5]
或許再加個 3 分, 於是又...
curved2 = []
for g in curved:
curved2.append(g + 4)
curved2
[42.5, 85.4, 51.300000000000004, 76.60000000000001, 99.7, 64.5, 82.10000000000001, 75.5]
換成 array, 又快又自然!
grad_arr = np.array(grades)
grad_arr
array([35, 74, 43, 66, 87, 55, 71, 65])
grad_arr * 1.1
array([38.5, 81.4, 47.3, 72.6, 95.7, 60.5, 78.1, 71.5])
看來還是再加個 3 分...
grad_arr * 1.1 + 4
array([42.5, 85.4, 51.3, 76.6, 99.7, 64.5, 82.1, 75.5])
一位老師成績這樣算的:
有位同學
這位同學的學期成績是多少?
grades = np.array([85, 70, 80])
weights = np.array([0.2, 0.35, 0.45])
wgrades = grades * weights
wgrades
array([17. , 24.5, 36. ])
wgrades.sum()
77.5
我們其實可以用 dot product (矩陣乘法) 算出來!
grades @ weights
77.5
很多同學一起來...
grades = np.array([[85, 70, 80],
[12, 88, 77],
[85, 91, 33]])
grades * weights
array([[17. , 24.5 , 36. ], [ 2.4 , 30.8 , 34.65], [17. , 31.85, 14.85]])
軸的概念!
wgrades = grades * weights
wgrades
array([[17. , 24.5 , 36. ], [ 2.4 , 30.8 , 34.65], [17. , 31.85, 14.85]])
wgrades.sum(axis=1)
array([77.5 , 67.85, 63.7 ])
當然我這麼算有點誤導大家...
grades @ weights
array([77.5 , 67.85, 63.7 ])
我把它弄成「正確的矩陣」呢?
weights.shape
(3,)
weights.reshape(3,1)
array([[0.2 ], [0.35], [0.45]])
grades @ weights.reshape(3,1)
array([[77.5 ], [67.85], [63.7 ]])
我們在數據分析, 常常要改 array 的型式。
先想辦法、用亂數做出 50 個數字的 array, 叫做 A 好了。
A = np.random.randint(0, 10, 50)
A
array([8, 9, 5, 2, 0, 7, 4, 1, 3, 7, 1, 9, 5, 4, 9, 3, 5, 9, 7, 9, 6, 5, 6, 7, 2, 9, 2, 9, 1, 6, 9, 6, 0, 7, 5, 1, 5, 7, 7, 8, 1, 4, 9, 9, 8, 3, 7, 2, 5, 3])
A.shape
(50,)
A.shape = (5,10)
A
array([[8, 9, 5, 2, 0, 7, 4, 1, 3, 7], [1, 9, 5, 4, 9, 3, 5, 9, 7, 9], [6, 5, 6, 7, 2, 9, 2, 9, 1, 6], [9, 6, 0, 7, 5, 1, 5, 7, 7, 8], [1, 4, 9, 9, 8, 3, 7, 2, 5, 3]])
但用 reshape
其實是比較好的方式...
A.reshape(10,5)
array([[8, 9, 5, 2, 0], [7, 4, 1, 3, 7], [1, 9, 5, 4, 9], [3, 5, 9, 7, 9], [6, 5, 6, 7, 2], [9, 2, 9, 1, 6], [9, 6, 0, 7, 5], [1, 5, 7, 7, 8], [1, 4, 9, 9, 8], [3, 7, 2, 5, 3]])
A
array([[8, 9, 5, 2, 0, 7, 4, 1, 3, 7], [1, 9, 5, 4, 9, 3, 5, 9, 7, 9], [6, 5, 6, 7, 2, 9, 2, 9, 1, 6], [9, 6, 0, 7, 5, 1, 5, 7, 7, 8], [1, 4, 9, 9, 8, 3, 7, 2, 5, 3]])
A = A.reshape(10, 5)
A
array([[8, 9, 5, 2, 0], [7, 4, 1, 3, 7], [1, 9, 5, 4, 9], [3, 5, 9, 7, 9], [6, 5, 6, 7, 2], [9, 2, 9, 1, 6], [9, 6, 0, 7, 5], [1, 5, 7, 7, 8], [1, 4, 9, 9, 8], [3, 7, 2, 5, 3]])
A.ravel()
array([8, 9, 5, 2, 0, 7, 4, 1, 3, 7, 1, 9, 5, 4, 9, 3, 5, 9, 7, 9, 6, 5, 6, 7, 2, 9, 2, 9, 1, 6, 9, 6, 0, 7, 5, 1, 5, 7, 7, 8, 1, 4, 9, 9, 8, 3, 7, 2, 5, 3])
A
array([[8, 9, 5, 2, 0], [7, 4, 1, 3, 7], [1, 9, 5, 4, 9], [3, 5, 9, 7, 9], [6, 5, 6, 7, 2], [9, 2, 9, 1, 6], [9, 6, 0, 7, 5], [1, 5, 7, 7, 8], [1, 4, 9, 9, 8], [3, 7, 2, 5, 3]])
np.zeros(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
np.zeros((3,4))
array([[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]])
np.eye(5)
array([[1., 0., 0., 0., 0.], [0., 1., 0., 0., 0.], [0., 0., 1., 0., 0.], [0., 0., 0., 1., 0.], [0., 0., 0., 0., 1.]])
np.ones((8,7))
array([[1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.]])
np.diag((1, 2, 3))
array([[1, 0, 0], [0, 2, 0], [0, 0, 3]])
很有趣的是...
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
A
array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
np.diag(A)
array([1, 5, 9])
array 有個很有趣的用法...
L = np.array([3, -2, -1, 5, 7, -3])
我們用另一個 array, 把「要的」標 True, 不要的標 False
want = np.array([True, False, False, True, True, False])
也就是我們只要正的...
L[want]
array([3, 5, 7])
其實我們可以這樣做...
L>0
array([ True, False, False, True, True, False])
L[L>0]
array([3, 5, 7])
a = np.array([1, 2, 3])
a.shape
(3,)
a.shape = (1,3)
L = np.array([3, -2, -1, 5, 7, -3, 87])
L
array([ 3, -2, -1, 5, 7, -3, 87])
L>0
array([ True, False, False, True, True, False, True])
L<10
array([ True, True, True, True, True, True, False])
(L>0) & (L<10)
array([ True, False, False, True, True, False, False])
L[(L>0) & (L<10)]
array([3, 5, 7])
x = np.linspace(-5, 5, 1000)
y = np.sinc(x)
plt.plot(x,y,lw=6)
plt.plot(x[y>0] , y[y>0], 'o')
[<matplotlib.lines.Line2D at 0x11c652438>]
import sympy as sym
1/2 + 1/3
0.8333333333333333
sym.Rational(1, 2) + sym.Rational(1, 3)
5/6
先來變美一點...
sym.init_printing()
sym.Rational(1, 2) + sym.Rational(1, 3)
更方便的做法 -- sympify
sym.S(1)/2 + sym.S(1)/3
這太常用了, 所以我們讀進來...
from sympy import S, N
S(1)/2 + S(1)/3
sym.pi
π = sym.pi
π
N(π, 20)
N(π, 10000)
什麼都在 π 中出現過...
pistring = str(N(π, 100000))
'1215' in pistring
True
'9487' in pistring
True
pistring.find('1215')
pistring[11942:11946]
'1215'
a = 9487
sym.isprime(a)
False
sym.factorint(9487)
53*179
sym.isprime(179)
True
sym.prime(87)
sym.nextprime(449)
for i in range(2, 50):
a = sym.prime(i)
b = sym.prime(i+1)
if b-a == 2:
print(f'{a} 和 {b} 是孿生質數!')
3 和 5 是孿生質數! 5 和 7 是孿生質數! 11 和 13 是孿生質數! 17 和 19 是孿生質數! 29 和 31 是孿生質數! 41 和 43 是孿生質數! 59 和 61 是孿生質數! 71 和 73 是孿生質數! 101 和 103 是孿生質數! 107 和 109 是孿生質數! 137 和 139 是孿生質數! 149 和 151 是孿生質數! 179 和 181 是孿生質數! 191 和 193 是孿生質數! 197 和 199 是孿生質數! 227 和 229 是孿生質數!
A = sym.Matrix([[2, -1, 3],
[0, 1, 2],
[-1, 1, 2]])
A.det()
A.inv()
x = sym.Symbol('x')
f = x**2 - 3*x + 2
f
sym.diff(f, x)
sym.integrate(f, x)
g = 5*x**2 - 3*x + 9
f + g
f * g
h = 3*k**2 - 3*k + 2
-------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-96-0b3b22298560> in <module>() ----> 1 h = 3*k**2 - 3*k + 2 NameError: name 'k' is not defined
from sympy.abc import x, y, z
f = sym.atan(x)
sym.diff(f, x)
sym.integrate(f, x)
sym.integrate(f, (x, 0, 1))
import pandas as pd
df = pd.read_csv('http://stats.moe.gov.tw/files/detail/107/107_student.csv')
df.head()
學校代碼 | 學校名稱 | 日間∕進修別 | 等級別 | 一年級男生 | 一年級女生 | 二年級男生 | 二年級女生 | 三年級男生 | 三年級女生 | ... | 五年級男生 | 五年級女生 | 六年級男生 | 六年級女生 | 七年級男生 | 七年級女生 | 延修生男生 | 延修生女生 | 縣市名稱 | 體系別 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 國立政治大學 | D 日 | D 博士 | 96 | 85 | 82 | 78 | 93 | 59 | ... | 71 | 52 | 58 | 46 | 74 | 40 | - | - | 30 臺北市 | 1 一般 |
1 | 1 | 國立政治大學 | D 日 | M 碩士 | 624 | 742 | 632 | 695 | 348 | 431 | ... | - | - | - | - | - | - | - | - | 30 臺北市 | 1 一般 |
2 | 1 | 國立政治大學 | D 日 | B 學士 | 899 | 1,287 | 890 | 1,332 | 878 | 1,325 | ... | - | - | - | - | - | - | 326 | 463 | 30 臺北市 | 1 一般 |
3 | 1 | 國立政治大學 | N 職 | M 碩士 | 303 | 248 | 253 | 259 | 201 | 210 | ... | 53 | 47 | - | - | - | - | - | - | 30 臺北市 | 1 一般 |
4 | 2 | 國立清華大學 | D 日 | D 博士 | 225 | 99 | 201 | 71 | 189 | 73 | ... | 158 | 50 | 112 | 43 | 168 | 58 | - | - | 18 新竹市 | 1 一般 |
5 rows × 22 columns
如果我們要算日間部, 用大學部一年級同學計算, 什麼學校女生比男生比例是最高的 (或男生比女生比例最高), 前 20 名要怎麼做呢?