認識常見的資料結構

Tidy datasets are all alike, but every messy dataset is messy in its own way.

Hadley Wickham

經過如何獲取資料的探討之後,我們已經暸解如何將常見的三個資料來源載入分析環境 Python 與 R 語言,接著要面對的課題是以適當的結構處理來源資料與轉換資料樣式,這兩類型的課題被總稱為 Data Wrangling(或者 Data Munging),Wrangling 或者 Munging 這兩個難以翻譯的動詞,傳達之意義就是掌控資料的能力,而掌控資料的能力建構在對資料結構的理解程度與操控資料框的技巧。

陣列

在科學計算中的運算單位往往不是單一數值(純量)而是一組數值,資料科學的陣列應用通常具備幾個特性:

  • 可以進行元素級別運算(element-wise operation)
  • 能夠不規則地選擇片段(slicing)
  • 能夠以判斷條件篩選
  • 僅容納單一型別

使用 Python 的 numpy.array() 方法與 R 語言的 c() 函數是最簡單建立陣列的方法,首先在終端機安裝 numpy 模組。

pip install numpy
1

以下展示的順序先是 Python 然後是 R 語言。

建立一個陣列,包含 11, 12, 13, 14, 15 這五個數字。

import numpy as np

arr = np.array([11, 12, 13, 14, 15])
print(arr)
print(type(arr))
1
2
3
4
5
## [11 12 13 14 15]
## <class 'numpy.ndarray'>
1
2
arr <- c(11, 12, 13, 14, 15)
arr
class(arr)
1
2
3
## [1] 11 12 13 14 15
## [1] "numeric"
1
2

若要從陣列中選出元素,可以使用中括號搭配元素的索引值,Python 的索引值左邊從 0 開始算起,右邊從 -1 開始算起;R 語言的索引值左邊從 1 開始算起。

import numpy as np

arr = np.array([11, 12, 13, 14, 15])

print(arr[0])         # 選最左邊
print(arr[-1])        # 選最右邊
print(arr[[0, 1, 4]]) # 不規則地選擇片段
1
2
3
4
5
6
7
## 11 
## 15
## [11 12 15]
1
2
3
arr <- c(11, 12, 13, 14, 15)
arr[1]           # 選最左邊
arr[length(arr)] # 選最右邊
arr[c(1, 2, 5)]  # 不規則地選擇片段
1
2
3
4
## [1] 11
## [1] 15
## [1] 11 12 15
1
2
3

如果希望更新其中元素的數值,只要選出來重新賦值即可,例如將 13 更換為 87。

import numpy as np

arr = np.array([11, 12, 13, 14, 15])
arr[2] = 87 # 將 13 更換為 87
print(arr)
1
2
3
4
5
## [11 12 87 14 15]
1
arr <- c(11, 12, 13, 14, 15)
arr[3] <- 87 # 將 13 更換為 87
arr
1
2
3
## [1] 11 12 87 14 15
1

假如希望新增數值,Python 可以使用 np.append() 或者 np.insert(),R 語言可以使用 c() 函數或 append() 函數。例如在原本的陣列中加入 87 與 99 兩個整數。

import numpy as np

arr = np.array([11, 12, 13, 14, 15])
arr = np.append(arr, 87)    # 在陣列的尾端加入 87
arr = np.insert(arr, 1, 99) # 在索引值 1 的位置加入 99
print(arr)
1
2
3
4
5
6
## [11 99 12 13 14 15 87]
1
arr <- c(11, 12, 13, 14, 15)
arr <- c(arr, 87)                          # 在陣列的尾端加入 87
arr <- append(arr, values = 99, after = 1) # 在索引值 1 之後加入 99
arr
1
2
3
4
## [1] 11 99 12 13 14 15 87
1

若要刪除數值 Python 可以使用 np.delete(),R 語言可以利用負索引值將特定數值刪除。例如在原本的陣列中刪除 13。

import numpy as np

arr = np.array([11, 12, 13, 14, 15])
arr = np.delete(arr, 2) # 刪除位於索引值 2 的 13
print(arr)
1
2
3
4
5
## [11 12 14 15]
1
arr <- c(11, 12, 13, 14, 15)
arr <- arr[-3] # 刪除位於索引值 3 的 13
arr
1
2
3
## [1] 11 12 14 15
1

陣列可以與一個純量或長度相同的陣列直接進行元素級別運算。

import numpy as np

arr = np.array([11, 12, 13, 14, 15])
print(arr + 2)   # 每個數字都加 2
print(arr - 2)   # 每個數字都減 2
print(arr * 2)   # 每個數字都乘 2
print(arr / 2)   # 每個數字都除以 2
print(arr**3)    # 每個數字都立方 
print(arr % 2)   # 每個數字除以 2 的餘數
print(arr // 2)  # 每個數字除以 2 的商數
print(arr + arr) # 對應位置的每個數字相加
print(arr * arr) # 對應位置的每個數字相乘
1
2
3
4
5
6
7
8
9
10
11
12
## [13 14 15 16 17]
## [ 9 10 11 12 13]
## [22 24 26 28 30]
## [5.5 6.  6.5 7.  7.5]
## [1331 1728 2197 2744 3375]
## [1 0 1 0 1]
## [5 6 6 7 7]
## [22 24 26 28 30]
## [121 144 169 196 225]
1
2
3
4
5
6
7
8
9
arr <- c(11, 12, 13, 14, 15)
arr + 2   # 每個數字都加 2
arr - 2   # 每個數字都減 2
arr * 2   # 每個數字都乘 2
arr / 2   # 每個數字都除以 2
arr**3    # 每個數字都立方
arr %% 2  # 每個數字除以 2 的餘數
arr %/% 2 # 每個數字除以 2 的商數
arr + arr # 對應位置的每個數字相加
arr * arr # 對應位置的每個數字相乘
1
2
3
4
5
6
7
8
9
10
## [1] 13 14 15 16 17
## [1]  9 10 11 12 13
## [1] 22 24 26 28 30
## [1] 5.5 6.0 6.5 7.0 7.5
## [1] 1331 1728 2197 2744 3375
## [1] 1 0 1 0 1
## [1] 5 6 6 7 7
## [1] 22 24 26 28 30
## [1] 121 144 169 196 225
1
2
3
4
5
6
7
8
9

實務上選擇陣列中的元素,更常見的是利用判斷條件篩選,例如從原有的數列中選出偶數:

import numpy as np

arr = np.array([11, 12, 13, 14, 15])
is_even = arr % 2 == 0
print(is_even)
print(arr[is_even])
1
2
3
4
5
6
## [False  True False  True False]
## [12 14]
1
2
arr <- c(11, 12, 13, 14, 15)
is_even <- arr %% 2 == 0
is_even
arr[is_even]
1
2
3
4
## [1] FALSE  TRUE FALSE  TRUE FALSE
## [1] 12 14
1
2

使用 for 迴圈可以迭代陣列,在 Python 中我們應用 enumerate() 函數同時取得索引與數值。

import numpy as np

arr = np.array([11, 12, 13, 14, 15])
for idx, val in enumerate(arr):
  print("位於索引值 {} 的數字是 {}".format(idx, val))
1
2
3
4
5
arr <- c(11, 12, 13, 14, 15)
for (idx in 1:length(arr)) {
  print(sprintf("位於索引值 %i 的數字是 %i", idx, arr[idx]))
}
1
2
3
4
## [1] "位於索引值 1 的數字是 11"
## [1] "位於索引值 2 的數字是 12"
## [1] "位於索引值 3 的數字是 13"
## [1] "位於索引值 4 的數字是 14"
## [1] "位於索引值 5 的數字是 15"
1
2
3
4
5

陣列僅能容納單一種型別,Python 與 R 語言的陣列都會自動做好型別轉換,優先順序由高至低依序為:文字、浮點數、整數與布林值(邏輯值),也就是說將布林值(邏輯值)與整數同時放置在陣列中時會都換為整數、若同時有布林值(邏輯值)、整數與浮點數則換為浮點數、假如有布林值(邏輯值)、整數、浮點數與文字就換為文字。

import numpy as np

arr = np.array([True, False, 87])      # 同時有布林值與整數換為整數
print(arr)
print(arr.dtype)
print("\n")
arr = np.append(arr, 8.7)              # 同時有布林值、整數與浮點數換為浮點數
print(arr)
print(arr.dtype)
print("\n")
arr = np.append(arr, "Luke Skywalker") # 同時有布林值、整數、浮點數與文字換為文字
print(arr)
print(arr.dtype)
1
2
3
4
5
6
7
8
9
10
11
12
13
## [ 1  0 87]
## int64
## 
## [ 1.   0.  87.   8.7]
## float64
##
## ['1.0' '0.0' '87.0' '8.7' 'Luke Skywalker']
## <U32
1
2
3
4
5
6
7
8
arr <- c(TRUE, FALSE, 87L)      # 同時有邏輯值與整數換為整數
arr
class(arr)
writeLines("\n")
arr <- c(arr, 8.7)              # 同時有邏輯值、整數與浮點數換為浮點數
arr
class(arr)
writeLines("\n")
arr <- c(arr, "Luke Skywalker") # 同時有邏輯值、整數、浮點數與文字換為文字
arr
class(arr)
1
2
3
4
5
6
7
8
9
10
11
## [1]  1  0 87
## [1] "integer"


## [1]  1.0  0.0 87.0  8.7
## [1] "numeric"


## [1] "1"              "0"              "87"             "8.7"            "Luke Skywalker"
## [1] "character"
1
2
3
4
5
6
7
8
9
10

向量、矩陣與張量

使用 Python 的 numpy.array() 方法與 R 語言的 matrix()array() 函數能夠建立出向量、矩陣與張量;向量其實就是一維陣列,外觀為 m x 1 的矩陣;矩陣則是 m x n 的二維陣列;三維以上的陣列均稱為張量。對 Python 而言,都只是外型不同的 ndarray,並沒有其他的型別;在 R 語言中 matrix 型別對應矩陣,array 型別對應張量。向量、矩陣與張量不過就是外型與維度更多的陣列,因此也都具備陣列的特性,像是可以進行元素級別運算(element-wise operation)、能夠不規則地選擇片段(slicing)、能夠以判斷條件篩選與僅容納單一型別等。

以下展示的順序先是 Python 然後是 R 語言。建立一個 5 x 1 的向量,包含 11, 12, 13, 14, 15 這五個數字。

import numpy as np

vec = np.array([11, 12, 13, 14, 15]).reshape(5, 1)
print(vec)
print(vec.shape)
1
2
3
4
5
## [[11]
##  [12]
##  [13]
##  [14]
##  [15]]
## (5, 1)
1
2
3
4
5
6
vec <- matrix(c(11, 12, 13, 14, 15))
vec
dim(vec)
1
2
3
##      [,1]
## [1,]   11
## [2,]   12
## [3,]   13
## [4,]   14
## [5,]   15
## [1] 5 1
1
2
3
4
5
6
7

建立一個 2 x 5 的矩陣,包含 11 到 20 這十個數字。

import numpy as np

mat = np.arange(11, 21).reshape(2, 5)
print(mat)
print(mat.shape)
1
2
3
4
5
## [[11 12 13 14 15]
##  [16 17 18 19 20]]
## (2, 5)
1
2
3
mat <- matrix(11:20, nrow = 2, byrow = TRUE)
mat
dim(mat)
1
2
3
##      [,1] [,2] [,3] [,4] [,5]
## [1,]   11   12   13   14   15
## [2,]   16   17   18   19   20
## [1] 2 5
1
2
3
4

建立一個外觀有 2 個 3 x 4 矩陣的張量,包含 11 到 34 這 24 個數字。Python 與 R 語言在張量外觀的描述上略有不同,像是 Python 描述外觀為 (2, 3, 4),而 R 語言則為 (3, 4, 2),而我們為了讓張量外觀相同(都依照列的方向去填滿)在 R 語言用了巢狀迴圈填滿。

import numpy as np

tensor = np.arange(11, 35).reshape(2, 3, 4)
print(tensor)
print(tensor.shape)
1
2
3
4
5
## [[[11 12 13 14]
##   [15 16 17 18]
##   [19 20 21 22]]
##  [[23 24 25 26]
##   [27 28 29 30]
##   [31 32 33 34]]]
## (2, 3, 4)
1
2
3
4
5
6
7
to_fill <- 11:34
tensor <- array(NA, c(3, 4, 2))
for (i in 1:2) {
  for (j in 1:3) {
    for (k in 1:4) {
      tensor[j, k, i] <- to_fill[1]
      to_fill <- to_fill[-1]
    }
  }
}
tensor
dim(tensor)
1
2
3
4
5
6
7
8
9
10
11
12
## , , 1

##      [,1] [,2] [,3] [,4]
## [1,]   11   12   13   14
## [2,]   15   16   17   18
## [3,]   19   20   21   22

## , , 2

##      [,1] [,2] [,3] [,4]
## [1,]   23   24   25   26
## [2,]   27   28   29   30
## [3,]   31   32   33   34

## [1] 3 4 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

若要從向量、矩陣或者張量中選出元素,與陣列相同可以使用中括號搭配元素的索引值,值得注意的一點是,現在的維度皆為 2 個以上,指定位置的時候記得依照維度給予索引值,例如分別從向量、矩陣與張量中選出 15 這個數字。

import numpy as np

vec = np.array([11, 12, 13, 14, 15]).reshape(5, 1)
mat = np.arange(11, 21).reshape(2, 5)
tensor = np.arange(11, 35).reshape(2, 3, 4)

print(vec[4, 0])       # 15 位於 (4, 0)    
print(mat[0, 4])       # 15 位於 (0, 4)
print(tensor[0, 1, 0]) # 15 位於 (0, 1, 0)
1
2
3
4
5
6
7
8
9
## 15
## 15
## 15
1
2
3
vec <- matrix(c(11, 12, 13, 14, 15))
mat <- matrix(11:20, nrow = 2, byrow = TRUE)
to_fill <- 11:34
tensor <- array(NA, c(3, 4, 2))
for (i in 1:2) {
  for (j in 1:3) {
    for (k in 1:4) {
      tensor[j, k, i] <- to_fill[1]
      to_fill <- to_fill[-1]
    }
  }
}
vec[5, 1]       # 15 位於 (5, 1)
mat[1, 5]       # 15 位於 (1, 5)
tensor[2, 1, 1] # 15 位於 (2, 1, 1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## [1] 15
## [1] 15
## [1] 15
1
2
3

我們同樣能利用判斷條件篩選向量、矩陣與張量中的元素,例如從其中選出偶數,篩選後的外型會還原成陣列。

import numpy as np

vec = np.array([11, 12, 13, 14, 15]).reshape(5, 1)
mat = np.arange(11, 21).reshape(2, 5)
tensor = np.arange(11, 35).reshape(2, 3, 4)

print(vec[vec % 2 == 0])
print(mat[mat % 2 == 0])
print(tensor[tensor % 2 == 0])
1
2
3
4
5
6
7
8
9
## [12 14]
## [12 14 16 18 20]
## [12 14 16 18 20 22 24 26 28 30 32 34]
1
2
3

vec <- matrix(c(11, 12, 13, 14, 15))
mat <- matrix(11:20, nrow = 2, byrow = TRUE)
to_fill <- 11:34
tensor <- array(NA, c(3, 4, 2))
for (i in 1:2) {
  for (j in 1:3) {
    for (k in 1:4) {
      tensor[j, k, i] <- to_fill[1]
      to_fill <- to_fill[-1]
    }
  }
}

vec[vec %% 2 == 0]
mat[mat %% 2 == 0]
tensor[tensor %% 2 == 0]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
## [1] 12 14
## [1] 16 12 18 14 20
## [1] 12 16 20 14 18 22 24 28 32 26 30 34
1
2
3

資料框

使用 Python 的 pandas.DataFrame() 方法與 R 語言的 data.frame() 函數能夠建立出資料框;資料框(Dataframe)是 Python 與 R 語言用來處理表格式資料(tabular data)的資料結構,它的外觀跟矩陣相似具有列與欄,但是增強了列索引值與欄索引值的功能,並容許每一個欄位(變數)具有自己的型別。資料科學團隊通常花費很多的時間與資料框周旋,我們會在後續章節詳細探討資料框操作技巧。

以下展示的順序先是 Python 然後是 R 語言。建立一個 1995 至 1996 年球季芝加哥公牛隊先發陣容的資料框,這是一個 5 x 2 的資料框,紀錄五個先發球員的背號與姓名。

import pandas as pd

numbers = [9, 23, 33, 91, 13]
players = ["Ron Harper", "Michael Jordan", "Scottie Pippen", "Dennis Rodman", "Luc Longley"]
df = pd.DataFrame()
df["number"] = numbers
df["players"] = players
df
1
2
3
4
5
6
7
8

5 x 2 的資料框,紀錄五個先發球員的背號與姓名

numbers <- c(9, 23, 33, 91, 13)
players <- c("Ron Harper", "Michael Jordan", "Scottie Pippen", "Dennis Rodman", "Luc Longley")
df <- data.frame(number = numbers, player = players, stringsAsFactors = FALSE)
View(df)
1
2
3
4

5 x 2 的資料框,紀錄五個先發球員的背號與姓名

在 Python 中一個資料框可以解構多組 Series,而 Series 又能解構為 ndarray;而 R 語言中一個資料框可以解構為多組陣列,因此可以理解為一但從資料框選出變數就具備了陣列特性,解構的方式為在中括號裡頭加入變數名稱,例如從資料框中選出 player 變數。

import pandas as pd

numbers = [9, 23, 33, 91, 13]
players = ["Ron Harper", "Michael Jordan", "Scottie Pippen", "Dennis Rodman", "Luc Longley"]
df = pd.DataFrame()
df["number"] = numbers
df["player"] = players
print(df["player"])              # 解構為 Series
print(type(df["player"]))
print(df["player"].values)       # 解構為 ndarray
print(type(df["player"].values))
1
2
3
4
5
6
7
8
9
10
11
## 0        Ron Harper
## 1    Michael Jordan
## 2    Scottie Pippen
## 3     Dennis Rodman
## 4       Luc Longley
## Name: player, dtype: object 
## <class 'pandas.core.series.Series'>
## ['Ron Harper' 'Michael Jordan' 'Scottie Pippen' 'Dennis Rodman'  'Luc Longley']
## <class 'numpy.ndarray'>
1
2
3
4
5
6
7
8
9
numbers <- c(9, 23, 33, 91, 13)
players <- c("Ron Harper", "Michael Jordan", "Scottie Pippen", "Dennis Rodman", "Luc Longley")
df <- data.frame(number = numbers, player = players, stringsAsFactors = FALSE)
df[, "player"]
class(df[, "player"])
1
2
3
4
5
## [1] "Ron Harper"     "Michael Jordan" "Scottie Pippen" "Dennis Rodman"  "Luc Longley"   
## [1] "character"
1
2

從資料框中選出元素可以使用中括號搭配元素的索引值,值得注意的一點是,現在的維度為 2,指定位置的時候應該以 [m, n] 的寫法,例如選出 Michael Jordan。

import pandas as pd

numbers = [9, 23, 33, 91, 13]
players = ["Ron Harper", "Michael Jordan", "Scottie Pippen", "Dennis Rodman", "Luc Longley"]
df = pd.DataFrame()
df["number"] = numbers
df["player"] = players
mj = df.iloc[1, 1]     # Michael Jordan 位於 (1, 1)
print(mj)
1
2
3
4
5
6
7
8
9
## Michael Jordan
1
numbers <- c(9, 23, 33, 91, 13)
players <- c("Ron Harper", "Michael Jordan", "Scottie Pippen", "Dennis Rodman", "Luc Longley")
df <- data.frame(number = numbers, player = players, stringsAsFactors = FALSE)
df[2, 2] # # Michael Jordan 位於 (2, 2)
1
2
3
4
## [1] "Michael Jordan"
1

利用判斷條件篩選資料框中的觀測值,例如從其中選出背號為 23、33 與 91 號的公牛隊鐵三角 Michael Jordan、Scottie Pippen 與 Dennis Rodman。我們有三個數字相等的條件,與其使用三個條件聯集(背號 == 23 | 背號 ==33 | 背號 == 91),我更推薦使用 in 這樣的判斷符號,寫起來比較簡潔。

import pandas as pd

numbers = [9, 23, 33, 91, 13]
players = ["Ron Harper", "Michael Jordan", "Scottie Pippen", "Dennis Rodman", "Luc Longley"]
df = pd.DataFrame()
df["number"] = numbers
df["player"] = players
trio = df["number"].isin([23, 33, 91])
print(trio)
df[trio]
1
2
3
4
5
6
7
8
9
10
## 0    False
## 1     True
## 2     True
## 3     True
## 4    False
## Name: number, dtype: bool
1
2
3
4
5
6

選出背號為 23、33 與 91 號的公牛隊鐵三角

numbers <- c(9, 23, 33, 91, 13)
players <- c("Ron Harper", "Michael Jordan", "Scottie Pippen", "Dennis Rodman", "Luc Longley")
df <- data.frame(number = numbers, player = players, stringsAsFactors = FALSE)
trio <- df[, "number"] %in% c(23, 33, 91)
trio
View(df[trio, ])
1
2
3
4
5
6
## [1] FALSE  TRUE  TRUE  TRUE FALSE
1

選出背號為 23、33 與 91 號的公牛隊鐵三角

關於更多資料框操作技巧,我們會在下兩個小節基礎資料框操作技巧進階資料框的操作技巧中詳細探討。

清單

資料科學團隊時常仰賴一種彈性極大的資料結構,彌補前述介紹資料結構為了便利科學計算而產生的侷限(例如陣列僅能儲存單一型別、資料框僅能處理對稱形式的表格等),這種彈性極大的資料結構在 Python 中是 list 與 dict 型別,而在 R 語言中則是 list 與有命名的 list,可以儲存任何型別、長度與外觀的資料,所對應的外部檔案格式就是 NoSQL 資料庫所使用的 JSON 檔案,例如使用清單類型的資料結構儲存 1995 至 1996 年的芝加哥公牛隊的一些基本資訊,這些資本資訊中,像是隊伍名稱和總教練是文字、助理教練則是 list 而戰績與先發陣容則是 dict(有命名的 list),從這裡就能夠對資料結構在儲存上具備的彈性一覽無遺。

以下展示的順序先是 Python 然後是 R 語言。

team_name = "Chicago Bulls"
season = "1995-96"
records = {
    "wins": 72,
    "losses": 10
}
coach = "Phil Jackson"
assistant_coach = ["Jim Cleamons", "John Paxson", "Jimmy Rodgers", "Tex Winter"]
starting_lineups = {
    "PG": "Ron Harper",
    "SG": "Michael Jordan",
    "SF": "Scottie Pippen",
    "PF": "Dennis Rodman",
    "C": "Luc Longley"
}

# 以 list 儲存
cb_list = [team_name, season, records, coach, assistant_coach, starting_lineups]
# 以 dict 儲存
cb_dict = {
    "team_name": team_name,
    "season": season,
    "records": records,
    "coach": coach,
    "assistant_coach": assistant_coach,
    "starting_lineups": starting_lineups
}
print(type(cb_list))
print(type(cb_dict))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
## <class 'list'>
## <class 'dict'>
1
2
team_name <- "Chicago Bulls"
season <- "1995-96"
records <- list(wins = 72, losses = 10)
coach <- "Phil Jackson"
assistant_coach <- c("Jim Cleamons", "John Paxson", "Jimmy Rodgers", "Tex Winter")
starting_lineups <- list(
  PG = "Ron Harper",
  SG = "Michael Jordan",
  SF = "Scottie Pippen",
  PF = "Dennis Rodman",
  C = "Luc Longley" 
)

# 以 list 儲存
cb_list <- list(team_name, season, records, coach, assistant_coach, starting_lineups)
# 以 named list 儲存
cb_named_list <- list(
  team_name = team_name,
  season = season,
  records = records,
  coach = coach,
  assistant_coach = assistant_coach,
  starting_lineups = starting_lineups
)
class(cb_list)
class(cb_named_list)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
## [1] "list"
## [1] "list"
1
2

在 Python 與 R 語言的 list 中選擇元素與陣列相同都是使用中括號與索引值(注意 R 語言要使用雙重中括號!)而 Python 的 dict 與 R 語言的 named list 既然有標籤(key),就改以標籤選擇。

team_name = "Chicago Bulls"
season = "1995-96"
records = {
    "wins": 72,
    "losses": 10
}
coach = "Phil Jackson"
assistant_coach = ["Jim Cleamons", "John Paxson", "Jimmy Rodgers", "Tex Winter"]
starting_lineups = {
    "PG": "Ron Harper",
    "SG": "Michael Jordan",
    "SF": "Scottie Pippen",
    "PF": "Dennis Rodman",
    "C": "Luc Longley"
}

# 以 list 儲存
cb_list = [team_name, season, records, coach, assistant_coach, starting_lineups]
# 以 dict 儲存
cb_dict = {
    "team_name": team_name,
    "season": season,
    "records": records,
    "coach": coach,
    "assistant_coach": assistant_coach,
    "starting_lineups": starting_lineups
}
print(cb_list[-2][1])                    # 選出助理教練 John Paxson
print(cb_dict["starting_lineups"]["SG"]) # 選出 Michael Jordan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
## John Paxson
## Michael Jordan
1
2
team_name <- "Chicago Bulls"
season <- "1995-96"
records <- list(wins = 72, losses = 10)
coach <- "Phil Jackson"
assistant_coach <- c("Jim Cleamons", "John Paxson", "Jimmy Rodgers", "Tex Winter")
starting_lineups <- list(
  PG = "Ron Harper",
  SG = "Michael Jordan",
  SF = "Scottie Pippen",
  PF = "Dennis Rodman",
  C = "Luc Longley" 
)

# 以 list 儲存
cb_list <- list(team_name, season, records, coach, assistant_coach, starting_lineups)
# 以 named list 儲存
cb_named_list <- list(
  team_name = team_name,
  season = season,
  records = records,
  coach = coach,
  assistant_coach = assistant_coach,
  starting_lineups = starting_lineups
)
cb_list[[5]][2]                             # 選出助理教練 John Paxson
cb_named_list[["starting_lineups"]][["SG"]] # 選出 Michael Jordan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
## [1] "John Paxson"
## [1] "Michael Jordan"
1
2

欲新增元素的時候,Python 的 list 使用 .append() 方法,而 R 語言使用 c() 函數;如果是 Python 的 dict 以及 R 語言的 named list 則可以指定一組新的標籤(key)與值(value)。

team_name = "Chicago Bulls"
season = "1995-96"
records = {
    "wins": 72,
    "losses": 10
}
coach = "Phil Jackson"
assistant_coach = ["Jim Cleamons", "John Paxson", "Jimmy Rodgers", "Tex Winter"]
starting_lineups = {
    "PG": "Ron Harper",
    "SG": "Michael Jordan",
    "SF": "Scottie Pippen",
    "PF": "Dennis Rodman",
    "C": "Luc Longley"
}

# 以 list 儲存
cb_list = [team_name, season, records, coach, assistant_coach, starting_lineups]
# 以 dict 儲存
cb_dict = {
    "team_name": team_name,
    "season": season,
    "records": records,
    "coach": coach,
    "assistant_coach": assistant_coach,
    "starting_lineups": starting_lineups
}

# 新增是否獲得總冠軍
is_champion = True
cb_list.append(is_champion)
cb_dict["is_champion"] = is_champion
print(cb_list[-1])            # 確認新增成功
print(cb_dict["is_champion"]) # 確認新增成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
## True
## True
1
2
team_name <- "Chicago Bulls"
season <- "1995-96"
records <- list(wins = 72, losses = 10)
coach <- "Phil Jackson"
assistant_coach <- c("Jim Cleamons", "John Paxson", "Jimmy Rodgers", "Tex Winter")
starting_lineups <- list(
  PG = "Ron Harper",
  SG = "Michael Jordan",
  SF = "Scottie Pippen",
  PF = "Dennis Rodman",
  C = "Luc Longley" 
)

# 以 list 儲存
cb_list <- list(team_name, season, records, coach, assistant_coach, starting_lineups)
# 以 named list 儲存
cb_named_list <- list(
  team_name = team_name,
  season = season,
  records = records,
  coach = coach,
  assistant_coach = assistant_coach,
  starting_lineups = starting_lineups
)
# 新增是否獲得總冠軍
is_champion <- TRUE
cb_list <- c(cb_list, is_champion)
cb_named_list[["is_champion"]] <- is_champion
cb_list[[length(cb_list)]]     # 確認新增成功
cb_named_list[["is_champion"]] # 確認新增成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
## [1] TRUE
## [1] TRUE
1
2

欲更新元素的時候,選擇出指定元素並賦值即可。

team_name = "Chicago Bulls"
season = "1995-96"
records = {
    "wins": 72,
    "losses": 10
}
coach = "Phil Jackson"
assistant_coach = ["Jim Cleamons", "John Paxson", "Jimmy Rodgers", "Tex Winter"]
starting_lineups = {
    "PG": "Ron Harper",
    "SG": "Michael Jordan",
    "SF": "Scottie Pippen",
    "PF": "Dennis Rodman",
    "C": "Luc Longley"
}

# 以 list 儲存
cb_list = [team_name, season, records, coach, assistant_coach, starting_lineups]
# 以 dict 儲存
cb_dict = {
    "team_name": team_name,
    "season": season,
    "records": records,
    "coach": coach,
    "assistant_coach": assistant_coach,
    "starting_lineups": starting_lineups
}

# 更新戰績
new_records = {
    "wins": 72,
    "losses": 10,
    "winning_percent": "{0:.2f}%".format(72/82*100)
}
cb_list[2] = new_records
cb_dict["records"] = new_records
print(cb_list[2])         # 確定更新成功
print(cb_dict["records"]) # 確定更新成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
## {'wins': 72, 'losses': 10, 'winning_percent': '87.80%'}
## {'wins': 72, 'losses': 10, 'winning_percent': '87.80%'}
1
2
team_name <- "Chicago Bulls"
season <- "1995-96"
records <- list(wins = 72, losses = 10)
coach <- "Phil Jackson"
assistant_coach <- c("Jim Cleamons", "John Paxson", "Jimmy Rodgers", "Tex Winter")
starting_lineups <- list(
  PG = "Ron Harper",
  SG = "Michael Jordan",
  SF = "Scottie Pippen",
  PF = "Dennis Rodman",
  C = "Luc Longley" 
)

# 以 list 儲存
cb_list <- list(team_name, season, records, coach, assistant_coach, starting_lineups)
# 以 named list 儲存
cb_named_list <- list(
  team_name = team_name,
  season = season,
  records = records,
  coach = coach,
  assistant_coach = assistant_coach,
  starting_lineups = starting_lineups
)

# 更新戰績
new_records <- list(
  wins = 72,
  losses = 10,
  winning_percent = sprintf("%.2f%%", 72/82*100)
)
cb_list[[3]] <- new_records
cb_named_list[["records"]] <- new_records
cb_list[[3]]               # 確定更新成功
cb_named_list[["records"]] # 確定更新成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
## $wins
## [1] 72

## $losses
## [1] 10

## $winning_percent
## [1] "87.80%"

## $wins
## [1] 72

## $losses
## [1] 10

## $winning_percent
## [1] "87.80%"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

使用 for 迴圈可以迭代 Python 與 R 語言的清單資料結構,在 Python 中面對 list 亦可以應用 enumerate() 同時取用索引與值,而面對 dict 則可以應用 .items() 方法同時取用標籤(key)與值。

team_name = "Chicago Bulls"
season = "1995-96"
records = {
    "wins": 72,
    "losses": 10
}
coach = "Phil Jackson"
assistant_coach = ["Jim Cleamons", "John Paxson", "Jimmy Rodgers", "Tex Winter"]
starting_lineups = {
    "PG": "Ron Harper",
    "SG": "Michael Jordan",
    "SF": "Scottie Pippen",
    "PF": "Dennis Rodman",
    "C": "Luc Longley"
}

# 以 list 儲存
cb_list = [team_name, season, records, coach, assistant_coach, starting_lineups]
# 以 dict 儲存
cb_dict = {
    "team_name": team_name,
    "season": season,
    "records": records,
    "coach": coach,
    "assistant_coach": assistant_coach,
    "starting_lineups": starting_lineups
}

# 迭代 list
for idx, elem in enumerate(cb_list):
  print("位於索引值 {} 的元素是:".format(idx))
  print(elem)
print("============")
# 迭代 dict
for key, value in cb_dict.items():
  print("位於標籤 {} 的值是:".format(key))
  print(value)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
## 位於索引值 0 的元素是:
## Chicago Bulls 
## 位於索引值 1 的元素是:
## 1995-96 
## 位於索引值 2 的元素是:
## {'wins': 72, 'losses': 10}
## 位於索引值 3 的元素是:
## Phil Jackson
## 位於索引值 4 的元素是:
## ['Jim Cleamons', 'John Paxson', 'Jimmy Rodgers', 'Tex Winter']
## 位於索引值 5 的元素是:
## {'PG': 'Ron Harper', 'SG': 'Michael Jordan', 'SF': 'Scottie Pippen', 'PF': 'Dennis Rodman', 'C': 'Luc Longley'}
## ============ 
## 位於標籤 team_name 的值是:
## Chicago Bulls
## 位於標籤 season 的值是:
## 1995-96
## 位於標籤 records 的值是:
## {'wins': 72, 'losses': 10}
## 位於標籤 coach 的值是:
## Phil Jackson
## 位於標籤 assistant_coach 的值是:
## ['Jim Cleamons', 'John Paxson', 'Jimmy Rodgers', 'Tex Winter']
## 位於標籤 starting_lineups 的值是:
## {'PG': 'Ron Harper', 'SG': 'Michael Jordan', 'SF': 'Scottie Pippen', 'PF': 'Dennis Rodman', 'C': 'Luc Longley'}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
team_name <- "Chicago Bulls"
season <- "1995-96"
records <- list(wins = 72, losses = 10)
coach <- "Phil Jackson"
assistant_coach <- c("Jim Cleamons", "John Paxson", "Jimmy Rodgers", "Tex Winter")
starting_lineups <- list(
  PG = "Ron Harper",
  SG = "Michael Jordan",
  SF = "Scottie Pippen",
  PF = "Dennis Rodman",
  C = "Luc Longley" 
)

# 以 list 儲存
cb_list <- list(team_name, season, records, coach, assistant_coach, starting_lineups)
# 以 named list 儲存
cb_named_list <- list(
  team_name = team_name,
  season = season,
  records = records,
  coach = coach,
  assistant_coach = assistant_coach,
  starting_lineups = starting_lineups
)
# 迭代 list
for (i in 1:length(cb_list)) {
  print(sprintf("位於索引值 %i 的元素是:", i))
  print(cb_list[[i]])
}
print("============")
# 迭代 named list
cb_list_names <- names(cb_named_list)
for (i in 1:length(cb_list_names)) {
  print(sprintf("位於標籤 %s 的元素是:", cb_list_names[i]))
  print(cb_named_list[[cb_list_names[i]]])
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
## [1] "位於索引值 1 的元素是:"
## [1] "Chicago Bulls"
## [1] "位於索引值 2 的元素是:"
## [1] "1995-96"
## [1] "位於索引值 3 的元素是:"
## $wins
## [1] 72

## $losses
## [1] 10

## [1] "位於索引值 4 的元素是:"
## [1] "Phil Jackson"
## [1] "位於索引值 5 的元素是:"
## [1] "Jim Cleamons"  "John Paxson"   "Jimmy Rodgers" "Tex Winter"   
## [1] "位於索引值 6 的元素是:"
## $PG
## [1] "Ron Harper"

## $SG
## [1] "Michael Jordan"

## $SF
## [1] "Scottie Pippen"

## $PF
## [1] "Dennis Rodman"

## $C
## [1] "Luc Longley"

## [1] "============"
## [1] "位於標籤 team_name 的元素是:"
## [1] "Chicago Bulls"
## [1] "位於標籤 season 的元素是:"
## [1] "1995-96"
## [1] "位於標籤 records 的元素是:"
## $wins
## [1] 72

## $losses
## [1] 10

## [1] "位於標籤 coach 的元素是:"
## [1] "Phil Jackson"
## [1] "位於標籤 assistant_coach 的元素是:"
## [1] "Jim Cleamons"  "John Paxson"   "Jimmy Rodgers" "Tex Winter"   
## [1] "位於標籤 starting_lineups 的元素是:"
## $PG
## [1] "Ron Harper"

## $SG
## [1] "Michael Jordan"

## $SF
## [1] "Scottie Pippen"

## $PF
## [1] "Dennis Rodman"

## $C
## [1] "Luc Longley"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

小結

在這個小節中我們簡介 Python 與 R 語言中常見的陣列、向量、矩陣、張量、資料框與清單,其中陣列、向量、矩陣與張量對應的 Python 資料結構均為 numpy.ndarray ,R 語言的資料結構則依序為 vector 、 matrix 與 array ;資料框對應的 Python 資料結構是 pandas.DataFrame ,R 語言則是 data.frame ;而清單對應的 Python 資料結構是 list 與 dict ,R 語言則是 list 與有命名的 list 。並依照資料結構特性適時探索如何應用化零為整(建立資料結構)、化整為零(選擇資料結構中的元素)、更新、刪除與迭代等操作技巧。

延伸閱讀