教你學會 Pandas 不是我的目的,教你輕鬆玩轉 Pandas 才是我的目的。我會通過一系列例項來帶入 Pandas 的知識點,讓你在學習 Pandas 的路上不再枯燥。
宣告:我所寫的輕鬆玩轉 Pandas 教程都是免費的,如果對你有幫助,你可以持續關注我。
Pandas 有很多高階的功能,但是想要掌握高階功能前,需要先掌握它的基礎知識,Pandas 中的資料結構算是非常基礎的知識之一了。
Pandas 常用的資料結構有兩種:Series 和 DataFrame。這些資料結構構建在 Numpy 陣列之上,這意味著它們效率很高。我們來分別看看這些資料結構都長什麼樣子吧。
# 匯入相關庫
import numpy as np
import pandas as pd
複製程式碼
Series
簡介
Series 是一個帶有 名稱 和索引的一維陣列,既然是陣列,肯定要說到的就是陣列中的元素型別,在 Series 中包含的資料型別可以是整數、浮點、字串、Python物件等。
假定有一個場景是:儲存一些使用者的資訊,暫時只包括年齡資訊。
我們可以通過 Series 來儲存,這裡我們通過 Series 儲存了四個年齡:18/30/25/40,只需將要儲存的資料構建成一個陣列,然後賦值給data引數即可。
# 儲存了 4 個年齡:18/30/25/40
user_age = pd.Series(data=[18, 30, 25, 40])
user_age
複製程式碼
0 18
1 30
2 25
3 40
dtype: int64
複製程式碼
可以看到,已經正確將多個年齡儲存到 Series 中了,你可能會想,單獨儲存了年齡有什麼用,我怎麼知道這個年齡屬於哪個使用者呢?
我們可以通過 Series 的 index(索引)來解決這個問題。由於有四個年齡,自然地也需要四個姓名,所以我們需要構建一個與 data 長度相同的陣列,然後通過下面的操作即可滿足要求。
user_age.index = ["Tom", "Bob", "Mary", "James"]
user_age
複製程式碼
Tom 18
Bob 30
Mary 25
James 40
dtype: int64
複製程式碼
你看,現在姓名與年齡已經完全對應上了。雖然說我們自己知道 Tom/Bob 這些是姓名,但是別人不知道啊,我們怎麼告訴他人呢?
要想讓別人知道,我們可以為 index 起個名字。
user_age.index.name = "name"
user_age
複製程式碼
name
Tom 18
Bob 30
Mary 25
James 40
dtype: int64
複製程式碼
可能你還會想,如果別人在看我寫的程式碼,怎麼能快速的知道我這寫的到底是什麼玩意呢?
別急,就像我們給index起名字一樣,我們也可以給 Series 起個名字。
user_age.name="user_age_info"
user_age
複製程式碼
name
Tom 18
Bob 30
Mary 25
James 40
Name: user_age_info, dtype: int64
複製程式碼
通過上面一系列的操作,我們對 Series 的結構上有了基本的瞭解,簡單來說,一個 Series 包括了 data、index 以及 name。
上面的操作非常方便做演示來使用,如果想要快速實現上面的功能,可以通過以下方式來實現。
# 構建索引
name = pd.Index(["Tom", "Bob", "Mary", "James"], name="name")
# 構建 Series
user_age = pd.Series(data=[18, 30, 25, 40], index=name, name="user_age_info")
user_age
複製程式碼
name
Tom 18
Bob 30
Mary 25
James 40
Name: user_age_info, dtype: int64
複製程式碼
另外,需要說明的是我們在構造 Series 的時候,並沒有設定每個元素的資料型別,這個時候,Pandas 會自動判斷一個資料型別,並作為 Series 的型別。
當然了,我們也可以自己手動指定資料型別。
# 指定型別為浮點型
user_age = pd.Series(data=[18, 30, 25, 40], index=name, name="user_age_info", dtype=float)
user_age
複製程式碼
name
Tom 18.0
Bob 30.0
Mary 25.0
James 40.0
Name: user_age_info, dtype: float64
複製程式碼
Series 像什麼
Series 包含了 dict 的特點,也就意味著可以使用與 dict 類似的一些操作。我們可以將 index 中的元素看成是 dict 中的 key。
# 獲取 Tom 的年齡
user_age["Tom"]
複製程式碼
18.0
複製程式碼
此外,可以通過 get 方法來獲取。通過這種方式的好處是當索引不存在時,不會丟擲異常。
user_age.get("Tom")
複製程式碼
18.0
複製程式碼
Series 除了像 dict 外,也非常像 ndarray,這也就意味著可以採用切片操作。
# 獲取第一個元素
user_age[0]
複製程式碼
18.0
複製程式碼
# 獲取前三個元素
user_age[:3]
複製程式碼
name
Tom 18.0
Bob 30.0
Mary 25.0
Name: user_age_info, dtype: float64
複製程式碼
# 獲取年齡大於30的元素
user_age[user_age > 30]
複製程式碼
name
James 40.0
Name: user_age_info, dtype: float64
複製程式碼
# 獲取第4個和第二個元素
user_age[[3, 1]]
複製程式碼
name
James 40.0
Bob 30.0
Name: user_age_info, dtype: float64
複製程式碼
可以看到,無論我們通過切片如何操作 Series ,它都能夠自動對齊 index。
Series 的向量化操作
Series 與 ndarray 一樣,也是支援向量化操作的。同時也可以傳遞給大多數期望 ndarray 的 NumPy 方法。
user_age + 1
複製程式碼
name
Tom 19.0
Bob 31.0
Mary 26.0
James 41.0
Name: user_age_info, dtype: float64
複製程式碼
np.exp(user_age)
複製程式碼
name
Tom 6.565997e+07
Bob 1.068647e+13
Mary 7.200490e+10
James 2.353853e+17
Name: user_age_info, dtype: float64
複製程式碼
DataFrame
DataFrame 是一個帶有索引的二維資料結構,每列可以有自己的名字,並且可以有不同的資料型別。你可以把它想象成一個 excel 表格或者資料庫中的一張表,DataFrame 是最常用的 Pandas 物件。
我們繼續使用之前的例項來講解 DataFrame,在儲存使用者資訊時,除了年齡之外,我還想儲存使用者所在的城市。如何通過 DataFrame 實現呢?
可以構建一個 dict,key 是需要儲存的資訊,value 是資訊列表。然後將 dict 傳遞給 data 引數。
index = pd.Index(data=["Tom", "Bob", "Mary", "James"], name="name")
data = {
"age": [18, 30, 25, 40],
"city": ["BeiJing", "ShangHai", "GuangZhou", "ShenZhen"]
}
user_info = pd.DataFrame(data=data, index=index)
user_info
複製程式碼
age | city | |
---|---|---|
name | ||
Tom | 18 | BeiJing |
Bob | 30 | ShangHai |
Mary | 25 | GuangZhou |
James | 40 | ShenZhen |
可以看到,我們成功構建了一個 DataFrame,這個 DataFrame 的索引是使用者性別,還有兩列分別是使用者的年齡和城市資訊。
除了上面這種傳入 dict 的方式構建外,我們還可以通過另外一種方式來構建。這種方式是先構建一個二維陣列,然後再生成一個列名稱列表。
data = [[18, "BeiJing"],
[30, "ShangHai"],
[25, "GuangZhou"],
[40, "ShenZhen"]]
columns = ["age", "city"]
user_info = pd.DataFrame(data=data, index=index, columns=columns)
user_info
複製程式碼
age | city | |
---|---|---|
name | ||
Tom | 18 | BeiJing |
Bob | 30 | ShangHai |
Mary | 25 | GuangZhou |
James | 40 | ShenZhen |
訪問行
在生成了 DataFrame 之後,可以看到,每一行就表示某一個使用者的資訊,假如我想要訪問 Tom 的資訊,我該如何操作呢?
一種辦法是通過索引名來訪問某行,這種辦法需要藉助 loc 方法。
user_info.loc["Tom"]
複製程式碼
age 18
city BeiJing
Name: Tom, dtype: object
複製程式碼
除了直接通過索引名來訪問某一行資料之外,還可以通過這行所在的位置來選擇這一行。
user_info.iloc[0]
複製程式碼
age 18
city BeiJing
Name: Tom, dtype: object
複製程式碼
現在能夠訪問某一個使用者的資訊了,那麼我如何訪問多個使用者的資訊呢?也就是如何訪問多行呢?
藉助行切片可以輕鬆完成,來看這裡。
user_info.iloc[1:3]
複製程式碼
age | city | |
---|---|---|
name | ||
Bob | 30 | ShangHai |
Mary | 25 | GuangZhou |
訪問列
學會了如何訪問行資料之外,自然而然會想到如何訪問列。我們可以通過屬性(“.列名”)的方式來訪問該列的資料,也可以通過[column]的形式來訪問該列的資料。
假如我想獲取所有使用者的年齡,那麼可以這樣操作。
user_info.age
複製程式碼
name
Tom 18
Bob 30
Mary 25
James 40
Name: age, dtype: int64
複製程式碼
user_info["age"]
複製程式碼
name
Tom 18
Bob 30
Mary 25
James 40
Name: age, dtype: int64
複製程式碼
如果想要同時獲取年齡和城市該如何操作呢?
# 可以變換列的順序
user_info[["city", "age"]]
複製程式碼
city | age | |
---|---|---|
name | ||
Tom | BeiJing | 18 |
Bob | ShangHai | 30 |
Mary | GuangZhou | 25 |
James | ShenZhen | 40 |
新增/刪除列
在生成了 DataFrame 之後,突然你發現好像缺失了使用者的性別這個資訊,那麼如何新增呢?
如果所有的性別都一樣,我們可以通過傳入一個標量,Pandas 會自動幫我們廣播來填充所有的位置。
user_info["sex"] = "male"
user_info
複製程式碼
age | city | sex | |
---|---|---|---|
name | |||
Tom | 18 | BeiJing | male |
Bob | 30 | ShangHai | male |
Mary | 25 | GuangZhou | male |
James | 40 | ShenZhen | male |
如果想要刪除某一列,可以使用 pop 方法來完成。
user_info.pop("sex")
user_info
複製程式碼
age | city | |
---|---|---|
name | ||
Tom | 18 | BeiJing |
Bob | 30 | ShangHai |
Mary | 25 | GuangZhou |
James | 40 | ShenZhen |
如果使用者的性別不一致的時候,我們可以通過傳入一個 like-list 來新增新的一列。
user_info["sex"] = ["male", "male", "female", "male"]
user_info
複製程式碼
age | city | sex | |
---|---|---|---|
name | |||
Tom | 18 | BeiJing | male |
Bob | 30 | ShangHai | male |
Mary | 25 | GuangZhou | female |
James | 40 | ShenZhen | male |
通過上面的例子可以看出,我們建立新的列的時候都是在原有的 DataFrame 上修改的,也就是說如果新增了新的一列之後,原有的 DataFrame 會發生改變。
如果想要保證原有的 DataFrame 不改變的話,我們可以通過 assign 方法來建立新的一列。
user_info.assign(age_add_one = user_info["age"] + 1)
複製程式碼
age | city | sex | age_add_one | |
---|---|---|---|---|
name | ||||
Tom | 18 | BeiJing | male | 19 |
Bob | 30 | ShangHai | male | 31 |
Mary | 25 | GuangZhou | female | 26 |
James | 40 | ShenZhen | male | 41 |
user_info.assign(sex_code = np.where(user_info["sex"] == "male", 1, 0))
複製程式碼
age | city | sex | sex_code | |
---|---|---|---|---|
name | ||||
Tom | 18 | BeiJing | male | 1 |
Bob | 30 | ShangHai | male | 1 |
Mary | 25 | GuangZhou | female | 0 |
James | 40 | ShenZhen | male | 1 |
想要學習更多關於人工智慧的知識,請關注公眾號:AI派
這裡我將整篇文章的內容整理成了pdf,想要pdf檔案的可以在公眾號後臺回覆關鍵字:pandas01。
更多Pandas知識見:輕鬆玩轉Pandas