# 汪群超 Chun-Chao Wang

Dept. of Statistics, National Taipei University, Taiwan

# Lesson 1: 基本 Python

## Objective:

1. 學習進入 Python 計算的基礎與法與指令。
2. 學習安裝套件、使用模組，譬如數學相關的 numpy 與統計計算相關的 scipy

## Prerequisite:

• 安裝 Python 與 Visual Studio Code (IDE) + Jupyter Notebook extensions 及其他客製化的 extensions。
• 熟悉在 Jupyter Notebook 的環境中，寫 $\LaTeX$ 數學式及其他文字表現。

1. 建立一個全新的目錄，並在 VS Code 中開啟，然後建立一個新檔案，檔名 lesson_1.py。輸入下列每個範例的每一行指令，執行並觀察結果。

2. 在 VS Code 中執行副檔名為 py 的程式，執行的目標地點為下方的 terminal 視窗。而且除非使用 print(變數名稱)，否則看不到執行結果。

3. 另一個執行方式是借用 Jupyter Notebook 的延伸功能，將程式執行交給 Jupyter Notebook。 做法：按程式視窗右鍵，選擇「Run Current File in Interactive Window」。此時，除了在右邊新增一 Jupyter 視窗外，在下面的 terminal 視窗也會多出一個「Jupyter”Variables」的選項，裡面呈現目前為止出現過的變數名稱，及其資料形態與內容。方便觀察變數內容，不一定要用 print()。

4. 下列的指令與語法的學習，採猜測的原則（從已經熟悉的某個語言）。從執行的結果去驗證。若還猜不到，可以上網查詢官網的說明。

5. 變數名稱盡量能自我說明，長一點無所謂。

6. Python 程式的格式有一定的樣子，可以使用 VS Code 的功能「Format Document」（按右鍵），程式碼會自動調整為較符合 coding 的原則。

#%% 1. Numbers

int_number = 1
float_number = 1.0
complex_number = 1 + 2j
round_float = round(1234.5678, 2)
str2int = int('213')

print(round_float)

# list and indexing

number_list = [0, 1, 1, 2, 3, 5, 8]
# the slicings use the zero-based indexing,
# that includes the lower bound and omit the upper bound, e.g.
print(number_list)  # indexing
print(number_list[0:3])  # [n, m] : slicing from index n to the mth position of the list
print(number_list[-1])  # the last one
print(number_list[-3:])  # the last three

list_list = [[1, 2, 3], [4, 5, 6]]  # list of list
print(list_list)
print(list_list[0:2])

# Explain why "indexing" starts from 0

a = [1, 2, 3, 4, 5, 6, 7]  # = np.arange(1, 8)
low, high = 2, 4
print(a[0:low] + a[low:high] + a[high:7])



注意事項：

1. 開始使用 numpy 套件建立矩陣. 安裝方式（在下方 terminal 視窗）: pip install numpy.

2. 使用 np.size() and np.shape() 觀察矩陣或向量的大小。

3. 練習向量與矩陣的索引（indexing）。

# Vector and indexing

import numpy as np

a = np.array([1, 2, 3]) # a vector has no direction
A = np.array([[1, 2, 3]]) # a 1 x 3 array that can be transposed
a_T = a[:, np.newaxis] # a'
A_T = A.T # A'
C = np.array([1, 2, 3], ndmin = 2) # convert a to A
print(np.size(a))  # number of elements
print(np.shape(A_T))  # array dimension

# Vector Indexing

A = np.array([[1, 2, 3],[4, 5, 6]])
print(A)
print(A.shape) # shape() is a method of a numpy array
print(A)
print(A[1,:])
print(A[:,1])
print(A[:,[0,2]])


# vector concatenate
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.concatenate((a, b), axis = 0) # flatten a, b
d = np.append(a, b)
e = np.hstack((a, b))
F = np.vstack((a, b))
g = np.r_[a, b]
G = np.c_[a, b]
H = (a, b)

#matrix concatenate

a = np.array([[1, 2, 3]])
b = np.array([[4, 5, 6]])

# Vertically, concatenate row-wisely
C = np.concatenate((a, b), axis = 0)
D = np.r_[a, b]
E = np.vstack((a,b))

# Horizontally, concatenate column-wisely
F = np.concatenate((a.T, b.T), axis =1)
G = np.hstack((a.T, b.T))
H = np.c_[a.T, b.T]

print(C)
print(C.max())
print(C.max(0)) # column max
print(np.max(C, axis = 1)) # row max


Note: The Difference Between a List and an Array in Python
Arrays and lists are both used in Python to store data, but they don’t serve exactly the same purposes. They both can be used to store any data type (real numbers, strings, etc), and they both can be indexed and iterated through, but the similarities between the two don’t go much further. The main difference between a list and an array is the functions that you can perform to them. For example, you can divide an array by 3, and each number in the array will be divided by 3 and the result will be printed if you request it. If you try to divide a list by 3, Python will tell you that it can’t be done, and an error will be thrown. (citation: Quick Tip: The Difference Between a List and an Array in Python)

tuple

a_tuple = (0, 0) # ordered sequence
also_a_tuple = 0, 0
a_3d_tuple = (0, 1, 2) # (2,1,0) is different, however the list  [0,1,2] := [1,2,0]


範例：Special matrices

A = np.array([[1, 2, 3],[4, 5, 6]])
a = A.flatten() # turn into vector
b = A.flatten('F') # turn into vector column-wise
A[A < 3] = 0

c = [1, 2, 3, 4]
C = np.tile(c,(5,1)) # = repmat in MATLAB
d = np.reshape(C, (-1, 1)) # convert to Column vector
print(C)
print(d)
print(C.flatten())

Z = np.zeros((3,4))
One =  np.ones((3,4))
I = np.eye(3)
D = np.diag(c) # D a diagonal matrix
e = np.diag(I) # the diagonal of I


範例：String and indexing

#%% string & indexing

s1 = 'a single quote string'
s2 = "a double quote string"
s3 = '''a triple quote string'''

print(type(s2))
print(s3)
print(s2[:4])
print(s3)

s4 = """
Triple double quotes
is usually used
in multiple lines, such as documents
"""

print(s4)

# concatenate strings
s5 = 'This is ' + s1
print(s5)

# string list
str_list = ['r', 'g', 'b', 'k', 'y']
print(str_list)

# Dictionaries similar to structure in MATLAB
meals = {'breakfast': 'sardines', 'lunch': 'salad', 'dinner': 'cake', 'cost':40}
print(meals['breakfast'])
print(meals['cost'])
print('The meal costs {} dollars'.format(meals['cost']))



範例：Sequencial numbers

import numpy as np

x0 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
x1 = range(1, 10, 1)
x2 = np.arange(1, 10, 1)  # integer
x3 = np.linspace(1, 9, 9)  # float number

x4 = np.arange(10)  # start from 0
x5 = np.linspace(0, 100, 1000)
# list and range type can not do math operations
y1 = x2 + x3 + 1
y2 = x2 ** 2 + x2 - 2
y3 = x2 / x3


範例：matrix operations

Let $X = \left[ \begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ \end{array} \right] \;\;,$ $A = \left[ \begin{array}{ccc} 1 & 1 & 1 \\ 2 & 4 & 6 \\ 5 & 7 & 6 \end{array} \right]\;\;\;,$ $b = \left[ \begin{array}{c} 1 \\ 2 \\ 3 \end{array} \right]$

仔細地計算下列每一個矩陣的運算。從結果去猜測指令的意思。

1. $X(1, 2)$
2. $P(i,j) = X(i,j) * X(i,j)$ for $1 \leq i \leq 2, 1\leq j\leq 3$
3. $Q(i,j) = X(i,j) / X(i,j)$ for $1 \leq i \leq 2, 1\leq j\leq 3$
4. $R = XX^T$
5. total_sum $=\sum_{i=1}^{2}\sum_{j=1}^{3} X(i,j)$
6. row_sum $r_i=\sum_{j=1}^{3} X(i,j), 1\leq i \leq2$
7. col_sum $c_j=\sum_{i=1}^{2} X(i,j), 1\leq i\leq 3$
8. $x =A^{-1}b$
9. $I = AA^{-1}$
10. $A^2$
11. $\sqrt{A}$
12. $B = \left[ \begin{array}{c} A \\ b^T \end{array} \right]$, i.e. add a new row vector after the last row of A.
13. $C = \left[ \begin{array}{cc} A & b \end{array} \right]$, i.e. add a new column vector after the last column of A.
from numpy import linalg
import numpy as np # numpy is a package
import scipy.linalg as LA # scipy's linear algebra is better

X = np.array([[1,2,3],[4,5,6]]) # a 2x3 matrix
# check the information of X
b = X.ndim
S = X.shape
s = X.size

a = X[0, 1]
P = X * X # element by element multiplication
Q = X / X
R = X @ X.T # XX'

total_sum = X.sum() # X.mean()...
row_sum = X.sum(axis = 1) # sum over each row
# col_sum = X.sum(axis = 0) # sum over each column
col_sum = np.sum(X, axis = 0)

A = np.array([[1, 1, 1],[2, 4, 6],[5, 7, 6]])
b = np.array([1, 2, 3])
x =  LA.inv(A) @ b  # Ax = b
xsol = LA.solve(A, b) # Ax = b
I = A @ LA.inv(A)

A_square = linalg.matrix_power(A, 2) # nth power of a matrix
A_square_root = LA.fractional_matrix_power(A, 0.5)

B = np.vstack((A, b)) # 4 x 3
C = np.hstack((A, b.reshape(3, 1))) # 3 x 4

B_row = np.insert(A, 3, b, 0) # 3 is the position index; 0 is for row
B_col = np.insert(A, 3, b, 1) # 3 is the position index; 1 is for column


範例：Logical operations

邏輯式運算非常好運，往往讓程式變得很簡潔。

import numpy as np

x = np.array([1, 2, 5, 3, 2])
x[x > 3] = 9 # replaced by 9; conditioned on x>3
y = np.where(x > 3, 9, x)
z = np.where(x >=3, 1, 0)

a = 3
if a > 1 and a < 5 :
print('TRUE')
else :
print('FALSE')

if a > 5 or a < 1 :
print('OUTSIDE')
else :
print('INSIDE')