二維的 DataFrame


對於經常面對 Excel 或資料庫表格的人來說,面對 Pandas 的 DataFrame 應該會感到熟悉,基本上,它就是用來表現二維的表格資料,例如,簡單的成績記錄在 Excel 可能是這麼記錄:

二維的 DataFrame

使用 Pandas 的話,可以透過 DataFrame 來建立對應的資料:

import pandas as pd

scores = pd.DataFrame({
    '數學' :  [90, 99, 92, 87, 85],
    '英文' :  [99, 87, 85, 67, 89],
    '物理' :  [100, 94, 76, 72, 67]
})

print(scores)

這會顯示以下的結果:

   數學  英文   物理
0  90  99  100
1  99  87   94
2  92  85   76
3  87  67   72
4  85  89   67

如果不想透過 dict,也可以透過個別指定行(Column)資料的方式來建立 DataFrame,這在程式碼的視覺上,會比較像是 Excel 之類的表格:

import pandas as pd

scores = pd.DataFrame(
    [
        [90, 99, 100],
        [99, 87, 94],
        [92, 85, 76],
        [87, 67, 72],
        [85, 89, 67]
    ],
    columns = ['數學', '英文', '物理']
)

print(scores)

顯示結果中最左邊顯示的是索引,就跟〈一維的 Series〉中類似的,DataFrame 的索引名稱是可以修改的,修改時也是透過 index,沒有指定的話,就自動從 0 開始編號作為索引名稱,類似地,如果上例沒有指定 columns,也是自動從 0 開始編號作為索引名稱,如果 columns 指定的數量大於資料,資料部份會自動設為:

底下的範例同時指定了 columnsindex

import pandas as pd

scores = pd.DataFrame(
    [
        [90, 99, 100],
        [99, 87, 94],
        [92, 85, 76],
        [87, 67, 72],
        [85, 89, 67]
    ],
    columns = ['數學', '英文', '物理'],
    index = ['No.01', 'No.02', 'No.03', 'No.04', 'No.05'],
)

print(scores)

這會顯示以下的結果:

       數學  英文   物理
No.01  90  99  100
No.02  99  87   94
No.03  92  85   76
No.04  87  67   72
No.05  85  89   67

若與 NumPy 二維陣列對比,DataFrameindex 相當於軸 0 索引,而 columns 相當於軸 1 索引,然而可以給予更具體的名稱。

DataFrame 的資料,也可以套用〈Universal 函式〉,例如全部分數減 5:

print(scores - 5)

結果會顯示以下:

       數學  英文  物理
No.01  85  94  95
No.02  94  82  89
No.03  87  80  71
No.04  82  62  67
No.05  80  84  62

如果想取得某行的資料,可以透過索引名稱。例如:

print(scores['數學'])

也可以寫為 scores.數學,在只有指定一行時,結果會以 Series 傳回,因而會顯示以下:

0    90
1    99
2    92
3    87
4    85
Name: 數學, dtype: int64

若要指定兩個以上的行,可以透過 list。例如:

print(scores[['數學', '物理']])

若指定的行是兩行以上,結果會以 DataFrame 傳回,因而會顯示以下結果:

   數學   物理
0  90  100
1  99   94
2  92   76
3  87   72
4  85   67

若要取得某列的話,必須透過 DataFrameloc 指定索引名稱。例如,取得 'No.02' 的資料:

print(scores.loc['No.02'])

當指定的列只有一行時,會以 Series 傳回,會顯示以下的結果:

數學    99
英文    87
物理    94
Name: No.02, dtype: int64

如果要指定多列的話,可以透過 list。例如:

 print(scores.loc[['No.02', 'No.04']])

若指定的行是兩行以上,結果會以 DataFrame 傳回,因而會顯示以下結果:

       數學  英文  物理
No.02  99  87  94
No.04  87  67  72

loc 也可以同時指定列、行,中間以逗號區隔,例如 No.01 列的 '數學' 行:

 print(scores.loc['No.01', '數學']) # 顯示 90

實際上這只指定了一個元素,對於對象會是一個元素的情況,建議使用 at

print(scores.at['No.01', '數學'])  # 顯示 90

loc 的應用場合在於指定多列多行,例如:

print(scores.loc[['No.01', 'No.03'], ['數學', '物理']])

這會顯示以下結果:

       數學   物理
No.01  90  100
No.03  92   76

在某些場合,你可能想要一整個範圍的列或行,這可以透過 iloci 表示整數索引,這可以實現〈NumPy 陣列索引〉中的 np.ix_ 的效果。例如:

print(scores.iloc[0:3,1:3])

這會顯示以下的結果:

       英文   物理
No.01  99  100
No.02  87   94
No.03  85   76

類似地,at 也有個對應的 iat,可以指定數字索引;如果是 scores.iloc[0:3],也可以簡寫為 scores[0:3]

NumPy 陣列索引〉看到的布林索引,也是行得通的,例如,找出數學大於 90 分的資料:

print(scores[scores.數學 > 90])

這會顯示以下的結果:

       數學  英文  物理
No.02  99  87  94
No.03  92  85  76

或者是找出物理小於 80 的物理分數:

print(scores.loc[scores.物理 < 80, '物理'])

這會顯示以下的結果:

No.03    76
No.04    72
No.05    67
Name: 物理, dtype: int64

可以就以上的試著多做一些嘗試與變化,做出各種不同的資料組合取法。