由 Pandas 的 DataFrame 中取得資料

由 Pandas 的 DataFrame 中取得資料

這篇文章參考了 Pandas 的官方教學文件「10分鐘短教學」,由其中截取 data selection 的部分的內容。
DataFrame 是 Pandas 中儲存 2 維表格的資料結構。我們可以將它視為類似 Excel 的試算表,或是關聯式資料庫中的一個表格。 底下我使用 Pandas 將這個 csv 讀入。
這個表格的 csv 可以由這兒下載。
In [2]:
import pandas as pd
student = pd.read_csv('student.csv', index_col = 0)
student
Out[2]:
Name height weight sex bdate city major
s1234567 Peter 175.0 70.45 1 1980/4/30 Tainan CSIE
e1234567 Mary 163.0 55.00 2 1981/12/21 Taipei EE
f1357689 John 180.4 80.30 1 1980/5/30 Tainan Stat
e1374659 Keven 182.5 77.60 1 1980/11/19 Taipei EE
s7758347 JoJo 170.3 50.30 2 1980/1/27 Taipei CSIE
s1334987 Emily 168.5 53.60 2 1982/10/13 Kaohsiung CSIE
e1384726 Ubuntu 177.0 68.30 1 1981/7/6 Kaohsiung EE

資料說明

上面的表格展示了學生的資料,第一個 column 是學號。之後依序是姓名、身高、體重、性別、生日、所在城市以及主修。

我們會想做什麼

如同我們在資料中下達 SQL 來取得資料,或者在分析資料。我們可能會希望做到底下的這些事:
  • 取出某些欄位 (column) 的資料,例如取得學生的姓名,以及身高
  • 過濾出某些資料,例如學生身高大於170的有誰,又例如住在 Tainai 的同學有誰,又例如體重介於75到80間的同學有誰…等。
  • 取出某些 row 的資料,例如學號為 s1234567 的學生是誰。

撈出學生的某些欄位的資料

把所有學生的姓名給列出來

Pandas 使用 [] 來取得 column 的資料,這個在我的 Pandas 系列文章中的第一篇有談到。
In [3]:
student['Name']
Out[3]:
s1234567     Peter
e1234567      Mary
f1357689      John
e1374659     Keven
s7758347      JoJo
s1334987     Emily
e1384726    Ubuntu
Name: Name, dtype: object
在 Pandas 中,每個 column 的 label,也可以視為 DataFrame 的一個屬性,因此你也可以使用下面的語法取得單一欄位的資料。
In [4]:
student.Name #使用屬性的方式取資料
Out[4]:
s1234567     Peter
e1234567      Mary
f1357689      John
e1374659     Keven
s7758347      JoJo
s1334987     Emily
e1384726    Ubuntu
Name: Name, dtype: object
當然,你也可以放一個 list 在 [] 中,取得單一欄位的資料。 要注意的事,當你使用 [[]] 來取得資料時,回傳的是一個 DataFrame,而不是一個 Series 了。
In [5]:
student[['Name']]
Out[5]:
Name
s1234567 Peter
e1234567 Mary
f1357689 John
e1374659 Keven
s7758347 JoJo
s1334987 Emily
e1384726 Ubuntu
取得多個欄位就一定要用到兩個 [] 了。底下的程式碼取得名字以及性別。

取得所有學生的名字,以及性別

In [6]:
student[['Name', 'sex']] # 要注意標籤的大小寫是有區別的
Out[6]:
Name sex
s1234567 Peter 1
e1234567 Mary 2
f1357689 John 1
e1374659 Keven 1
s7758347 JoJo 2
s1334987 Emily 2
e1384726 Ubuntu 1

取得 row 的資料

你可以使用 slice 語法,配合 [] 來取得 row 的資料。
也可以使用 loc,或是 iloc 來取得 row 的資料。
底下的程式碼取得索引值 0 到 2 的 rows 的資料。
In [7]:
student[0:3]  # 取得索引值 0-2 的資料,注意區間是左閉右開, 3 的部分是沒被包含進去的。
Out[7]:
Name height weight sex bdate city major
s1234567 Peter 175.0 70.45 1 1980/4/30 Tainan CSIE
e1234567 Mary 163.0 55.00 2 1981/12/21 Taipei EE
f1357689 John 180.4 80.30 1 1980/5/30 Tainan Stat

使用 loc 取 row 的資料

loc 是 label based 的資料取法,它可以使用底下幾種方式設定 label 來取得資料:
  1. 使用單一 label,例如 loc['s1234567'].
  2. 使用多個 labels, 例如 loc[['s1234567', 'e1234567']],請注意,這兒有兩個 []。
  3. 使用 slice 語法,例如 loc['s1234567':'e1374659'],請注意,這兒只有一個 []。
  4. 使用 boolean array,這部分會獨立一節出來談。
底下的語法使用 row 的標籤來取得某些 row 的資料
In [8]:
student.loc['s1234567'] #取得單一個 row 的資料,注意回傳為一個 series
Out[8]:
Name          Peter
height          175
weight        70.45
sex               1
bdate     1980/4/30
city         Tainan
major          CSIE
Name: s1234567, dtype: object
In [9]:
student.loc[['s1234567', 'e1234567']] ##注意有兩個 [],回傳為一個 DataFrame
Out[9]:
Name height weight sex bdate city major
s1234567 Peter 175.0 70.45 1 1980/4/30 Tainan CSIE
e1234567 Mary 163.0 55.00 2 1981/12/21 Taipei EE
In [10]:
#用 slice 來取得一個區間中的資料。注意這兒的 slice 沒有符合 Python 的習慣。這個區間是左閉,右閉的。
#也就是說,右邊的邊界是有包含的!
student.loc['s1234567':'e1374659'] 
Out[10]:
Name height weight sex bdate city major
s1234567 Peter 175.0 70.45 1 1980/4/30 Tainan CSIE
e1234567 Mary 163.0 55.00 2 1981/12/21 Taipei EE
f1357689 John 180.4 80.30 1 1980/5/30 Tainan Stat
e1374659 Keven 182.5 77.60 1 1980/11/19 Taipei EE
既然可以取得 row 的資料,當然也可以設定取某些 column。
例如想取得所有學生的名字及性別,也可以使用底下的語法。
In [11]:
student.loc[:, ['Name', 'sex']] #第 1 個 : 代表全部都要的意思
Out[11]:
Name sex
s1234567 Peter 1
e1234567 Mary 2
f1357689 John 1
e1374659 Keven 1
s7758347 JoJo 2
s1334987 Emily 2
e1384726 Ubuntu 1
取得某些學生的名字以及性別。
In [12]:
student.loc[['s1234567', 'e1374659'], ['Name', 'sex']]
Out[12]:
Name sex
s1234567 Peter 1
e1374659 Keven 1

使用 iloc 來取得資料

iloc 是 index based 取資料的方式。它可以使用底下的方式來取得資料。
  1. 使用單一個整數來取得資料,例如 iloc[5]。
  2. 使用一串整數來取得資料,例如 iloc[[1,3,5]]。
  3. 使用 slice 來取得資料,例如 iloc[1:3]
  4. 使用 boolean array,這部分會獨立一節來說明。
In [13]:
student.iloc[0] #單一整數,取得一個 series
Out[13]:
Name          Peter
height          175
weight        70.45
sex               1
bdate     1980/4/30
city         Tainan
major          CSIE
Name: s1234567, dtype: object
In [14]:
student.iloc[[0]] #單一整數,取得一個 DataFrame
Out[14]:
Name height weight sex bdate city major
s1234567 Peter 175.0 70.45 1 1980/4/30 Tainan CSIE
In [15]:
student.iloc[[0, 2, 4]] #取得多個 row
Out[15]:
Name height weight sex bdate city major
s1234567 Peter 175.0 70.45 1 1980/4/30 Tainan CSIE
f1357689 John 180.4 80.30 1 1980/5/30 Tainan Stat
s7758347 JoJo 170.3 50.30 2 1980/1/27 Taipei CSIE
In [16]:
#使用 slice,注意這兒的 slice 就符合 Python slice 的規範了,是左閉右開,右邊是不包含的。
student.iloc[0:3] 
Out[16]:
Name height weight sex bdate city major
s1234567 Peter 175.0 70.45 1 1980/4/30 Tainan CSIE
e1234567 Mary 163.0 55.00 2 1981/12/21 Taipei EE
f1357689 John 180.4 80.30 1 1980/5/30 Tainan Stat

使用 boolean array 來取得資料

Boolean array 就是一個串列,其中包含一群 boolean 值。
這個 boolean array 可以視為一個 遮罩,可以把 false 的部分遮掉,讓它不秀出來。
這樣講有點抽象,來看個例子。
列出表格中所有性別為 1 的學生的資料!
In [17]:
#先把所有性別為 1 的 row 都列出來
#底下的語法會把 == 對 sex 這個 column 的每個值都做一次運算
sex_1 = student['sex'] == 1
print(sex_1)
s1234567     True
e1234567    False
f1357689     True
e1374659     True
s7758347    False
s1334987    False
e1384726     True
Name: sex, dtype: bool
In [18]:
#接著使用 sex_1 來濾掉性別不為 1 的學生
student[sex_1]
Out[18]:
Name height weight sex bdate city major
s1234567 Peter 175.0 70.45 1 1980/4/30 Tainan CSIE
f1357689 John 180.4 80.30 1 1980/5/30 Tainan Stat
e1374659 Keven 182.5 77.60 1 1980/11/19 Taipei EE
e1384726 Ubuntu 177.0 68.30 1 1981/7/6 Kaohsiung EE
在上面的程式碼中,只要 sex_1 中為 false 的 row,都會被濾掉。所以剩下的,就是 sex == 1 的學生了。
程式碼也可以整合成一行來寫,如下所示。
In [19]:
student[student['sex'] == 1]
Out[19]:
Name height weight sex bdate city major
s1234567 Peter 175.0 70.45 1 1980/4/30 Tainan CSIE
f1357689 John 180.4 80.30 1 1980/5/30 Tainan Stat
e1374659 Keven 182.5 77.60 1 1980/11/19 Taipei EE
e1384726 Ubuntu 177.0 68.30 1 1981/7/6 Kaohsiung EE
除了 == 之外,其它像是 >、<、>=、<=、!= 也都可以使用。
底下程式碼列出不住在台南的所有學生的資料。
In [20]:
student[student['city'] != 'Tainan']
Out[20]:
Name height weight sex bdate city major
e1234567 Mary 163.0 55.0 2 1981/12/21 Taipei EE
e1374659 Keven 182.5 77.6 1 1980/11/19 Taipei EE
s7758347 JoJo 170.3 50.3 2 1980/1/27 Taipei CSIE
s1334987 Emily 168.5 53.6 2 1982/10/13 Kaohsiung CSIE
e1384726 Ubuntu 177.0 68.3 1 1981/7/6 Kaohsiung EE
那如果要多個布林邏輯的運算呢?例如要取得身高在 172.5 以上,但在 182.5 以下的學生有那些。
這個時候就要使用 numpy 的 logical_and 函式了。
In [21]:
import numpy as np
condition = np.logical_and(student['height']>=172.5, student['height']<=182.5) ## 找出那些 row 符合 >=172.5 且 <= 182.5 的條件
condition
Out[21]:
s1234567     True
e1234567    False
f1357689     True
e1374659     True
s7758347    False
s1334987    False
e1384726     True
Name: height, dtype: bool
In [22]:
student[condition]
Out[22]:
Name height weight sex bdate city major
s1234567 Peter 175.0 70.45 1 1980/4/30 Tainan CSIE
f1357689 John 180.4 80.30 1 1980/5/30 Tainan Stat
e1374659 Keven 182.5 77.60 1 1980/11/19 Taipei EE
e1384726 Ubuntu 177.0 68.30 1 1981/7/6 Kaohsiung EE
numpy 中可以對 numpy array 做邏輯運算的有:

使用 at 及 iat 來取得單一值

at 和 loc 一樣,都是 label-based 的取值方式。不同處在於 at 用於取單一值,且其運作速度快於 loc。 iat 和 iloc 一樣,都是 index-based 的取值方式。不同處在於 iat 用於取單一值,且其運作速度快於 iloc。
In [24]:
student.at['e1234567','Name'] # 取得 'e1234567' 這位學生的名字
Out[24]:
'Mary'
In [27]:
print(student.iat[0,0]) #取得 [0, 0] 這個位置的學生的名字
type(student.iat[0,0])
Peter
Out[27]:
str

結語

這篇文章中,談到了如何在 series 以及 DataFrame 中取得資料的方式。
此外,也談到了如何使用 boolean array 來做為遮罩,用來過濾資料,將 DataFrame 中我們想要抓的資料找出來。

留言

這個網誌中的熱門文章

[程式設計] C++ 的字串切割

[C++]在 cin 後呼叫 getline 所遇到的問題