Pandas是Wes McKinney在2008年開發的一個強大的分析結構化資料的工具集。Pandas以NumPy為基礎(資料表示和運算),提供了用於資料處理的函式和方法,對資料分析和資料探勘提供了很好的支援;同時Pandas還可以跟資料視覺化工具Matplotlib很好的整合在一起,非常輕鬆愉快的實現資料的視覺化展示。
Pandas核心的資料型別是Series
(資料系列)、DataFrame
(資料表/資料框),分別用於處理一維和二維的資料,除此之外還有一個名為Index
的型別及其子型別,它為Series
和DataFrame
提供了索引功能。日常工作中以DataFrame
使用最為廣泛,因為二維的資料本質就是一個有行有列的表格(想一想Excel電子表格和關係型資料庫中的二維表)。上述這些型別都提供了大量的處理資料的方法,資料分析師可以以此為基礎實現對資料的各種常規處理。
Pandas庫中的Series
物件可以用來表示一維資料結構,跟陣列非常類似,但是多了一些額外的功能。Series
的內部結構包含了兩個陣列,其中一個用來儲存資料,另一個用來儲存資料的索引。
提示:在執行下面的程式碼之前,請先匯入
pandas
以及相關的庫檔案,具體的做法可以參考上一章。
程式碼:
# data引數表示資料,index引數表示資料的索引(標籤)
# 如果沒有指定index屬性,預設使用數字索引
ser1 = pd.Series(data=[320, 180, 300, 405], index=['一季度', '二季度', '三季度', '四季度'])
ser1
輸出:
一季度 320
二季度 180
三季度 300
四季度 405
dtype: int64
程式碼:
# 字典中的鍵就是資料的索引(標籤),字典中的值就是資料
ser2 = pd.Series({'一季度': 320, '二季度': 180, '三季度': 300, '四季度': 405})
ser2
輸出:
一季度 320
二季度 180
三季度 300
四季度 405
dtype: int64
跟陣列一樣,Series物件也可以進行索引和切片操作,不同的是Series物件因為內部維護了一個儲存索引的陣列,所以除了可以使用整數索引透過位置檢索資料外,還可以透過自己設定的索引標籤獲取對應的資料。
程式碼:
print(ser2[0], ser[1], ser[2], ser[3])
ser2[0], ser2[3] = 350, 360
print(ser2)
輸出:
320 180 300 405
一季度 350
二季度 180
三季度 300
四季度 360
dtype: int64
提示:如果要使用負向索引,必須在建立
Series
物件時透過index
屬性指定非數值型別的標籤。
程式碼:
print(ser2['一季度'], ser2['三季度'])
ser2['一季度'] = 380
print(ser2)
輸出:
350 300
一季度 380
二季度 180
三季度 300
四季度 360
dtype: int64
程式碼:
print(ser2[1:3])
print(ser2['二季度':'四季度'])
輸出:
二季度 180
三季度 300
dtype: int64
二季度 500
三季度 500
四季度 520
dtype: int64
程式碼:
ser2[1:3] = 400, 500
ser2
輸出:
一季度 380
二季度 400
三季度 500
四季度 360
dtype: int64
程式碼:
print(ser2[['二季度', '四季度']])
ser2[['二季度', '四季度']] = 500, 520
print(ser2)
輸出:
二季度 400
四季度 360
dtype: int64
一季度 380
二季度 500
三季度 500
四季度 520
dtype: int64
程式碼:
ser2[ser2 >= 500]
輸出:
二季度 500
三季度 500
四季度 520
dtype: int64
####屬性和方法
Series物件的常用屬性如下表所示。
屬性 | 說明 |
---|---|
dtype / dtypes |
返回Series 物件的資料型別 |
hasnans |
判斷Series 物件中有沒有空值 |
at / iat |
透過索引訪問Series 物件中的單個值 |
loc / iloc |
透過一組索引訪問Series 物件中的一組值 |
index |
返回Series 物件的索引 |
is_monotonic |
判斷Series 物件中的資料是否單調 |
is_monotonic_increasing |
判斷Series 物件中的資料是否單調遞增 |
is_monotonic_decreasing |
判斷Series 物件中的資料是否單調遞減 |
is_unique |
判斷Series 物件中的資料是否獨一無二 |
size |
返回Series 物件中元素的個數 |
values |
以ndarray 的方式返回Series 物件中的值 |
Series
物件的方法很多,我們透過下面的程式碼為大家介紹一些常用的方法。
Series
物件支援各種獲取描述性統計資訊的方法。
程式碼:
# 求和
print(ser2.sum())
# 求均值
print(ser2.mean())
# 求最大
print(ser2.max())
# 求最小
print(ser2.min())
# 計數
print(ser2.count())
# 求標準差
print(ser2.std())
# 求方差
print(ser2.var())
# 求中位數
print(ser2.median())
Series
物件還有一個名為describe()
的方法,可以獲得上述所有的描述性統計資訊,如下所示。
程式碼:
ser2.describe()
輸出:
count 4.000000
mean 475.000000
std 64.031242
min 380.000000
25% 470.000000
50% 500.000000
75% 505.000000
max 520.000000
dtype: float64
提示:因為
describe()
返回的也是一個Series
物件,所以也可以用ser2.describe()['mean']
來獲取平均值。
如果Series
物件有重複的值,我們可以使用unique()
方法獲得去重之後的Series
物件;可以使用nunique()
方法統計不重複值的數量;如果想要統計每個值重複的次數,可以使用value_counts()
方法,這個方法會返回一個Series
物件,它的索引就是原來的Series
物件中的值,而每個值出現的次數就是返回的Series
物件中的資料,在預設情況下會按照出現次數做降序排列。
程式碼:
ser3 = pd.Series(data=['apple', 'banana', 'apple', 'pitaya', 'apple', 'pitaya', 'durian'])
ser3.value_counts()
輸出:
apple 3
pitaya 2
durian 1
banana 1
dtype: int64
程式碼:
ser3.nunique()
輸出:
4
Series
物件的isnull()
和notnull()
方法可以用於空值的判斷,程式碼如下所示。
程式碼:
ser4 = pd.Series(data=[10, 20, np.NaN, 30, np.NaN])
ser4.isnull()
輸出:
0 False
1 False
2 True
3 False
4 True
dtype: bool
程式碼:
ser4.notnull()
輸出:
0 True
1 True
2 False
3 True
4 False
dtype: bool
Series
物件的dropna()
和fillna()
方法分別用來刪除空值和填充空值,具體的用法如下所示。
程式碼:
ser4.dropna()
輸出:
0 10.0
1 20.0
3 30.0
dtype: float64
程式碼:
# 將空值填充為40
ser4.fillna(value=40)
輸出:
0 10.0
1 20.0
2 40.0
3 30.0
4 40.0
dtype: float64
程式碼:
# backfill或bfill表示用後一個元素的值填充空值
# ffill或pad表示用前一個元素的值填充空值
ser4.fillna(method='ffill')
輸出:
0 10.0
1 20.0
2 20.0
3 30.0
4 30.0
dtype: float64
需要提醒大家注意的是,dropna()
和fillna()
方法都有一個名為inplace
的引數,它的預設值是False
,表示刪除空值或填充空值不會修改原來的Series
物件,而是返回一個新的Series
物件來表示刪除或填充空值後的資料系列,如果將inplace
引數的值修改為True
,那麼刪除或填充空值會就地操作,直接修改原來的Series
物件,那麼方法的返回值是None
。後面我們會接觸到的很多方法,包括DataFrame
物件的很多方法都會有這個引數,它們的意義跟這裡是一樣的。
Series
物件的mask()
和where()
方法可以將滿足或不滿足條件的值進行替換,如下所示。
程式碼:
ser5 = pd.Series(range(5))
ser5.where(ser5 > 0)
輸出:
0 NaN
1 1.0
2 2.0
3 3.0
4 4.0
dtype: float64
程式碼:
ser5.where(ser5 > 1, 10)
輸出:
0 10
1 10
2 2
3 3
4 4
dtype: int64
程式碼:
ser5.mask(ser5 > 1, 10)
輸出:
0 0
1 1
2 10
3 10
4 10
dtype: int64
Series
物件的duplicated()
方法可以幫助我們找出重複的資料,而drop_duplicates()
方法可以幫我們刪除重複資料。
程式碼:
ser3.duplicated()
輸出:
0 False
1 False
2 True
3 False
4 True
5 True
6 False
dtype: bool
程式碼:
ser3.drop_duplicates()
輸出:
0 apple
1 banana
3 pitaya
6 durian
dtype: object
Series
物件的apply()
和map()
方法非常重要,它們可以用於資料處理,把資料對映或轉換成我們期望的樣子,這個操作在資料分析的資料準備階段非常重要。
程式碼:
ser6 = pd.Series(['cat', 'dog', np.nan, 'rabbit'])
ser6
輸出:
0 cat
1 dog
2 NaN
3 rabbit
dtype: object
程式碼:
ser6.map({'cat': 'kitten', 'dog': 'puppy'})
輸出:
0 kitten
1 puppy
2 NaN
3 NaN
dtype: object
程式碼:
ser6.map('I am a {}'.format, na_action='ignore')
輸出:
0 I am a cat
1 I am a dog
2 NaN
3 I am a rabbit
dtype: object
程式碼:
ser7 = pd.Series([20, 21, 12], index=['London', 'New York', 'Helsinki'])
ser7
輸出:
London 20
New York 21
Helsinki 12
dtype: int64
程式碼:
ser7.apply(np.square)
輸出:
London 400
New York 441
Helsinki 144
dtype: int64
程式碼:
ser7.apply(lambda x, value: x - value, args=(5, ))
輸出:
London 15
New York 16
Helsinki 7
dtype: int64
Series
物件的sort_index()
和sort_values()
方法可以用於對索引和資料的排序,排序方法有一個名為ascending
的布林型別引數,該引數用於控制排序的結果是升序還是降序;而名為kind
的引數則用來控制排序使用的演算法,預設使用了quicksort
,也可以選擇mergesort
或heapsort
;如果存在空值,那麼可以用na_position
引數空值放在最前還是最後,預設是last
,程式碼如下所示。
程式碼:
ser8 = pd.Series(
data=[35, 96, 12, 57, 25, 89],
index=['grape', 'banana', 'pitaya', 'apple', 'peach', 'orange']
)
# 按值從小到大排序
ser8.sort_values()
輸出:
pitaya 12
peach 25
grape 35
apple 57
orange 89
banana 96
dtype: int64
程式碼:
# 按索引從大到小排序
ser8.sort_index(ascending=False)
輸出:
pitaya 12
peach 25
orange 89
grape 35
banana 96
apple 57
dtype: int64
如果要從Series
物件中找出元素中最大或最小的“Top-N”,實際上是不需要對所有的值進行排序的,可以使用nlargest()
和nsmallest()
方法來完成,如下所示。
程式碼:
# 值最大的3個
ser8.nlargest(3)
輸出:
banana 96
orange 89
apple 57
dtype: int64
程式碼:
# 值最小的2個
ser8.nsmallest(2)
輸出:
pitaya 12
peach 25
dtype: int64
Series物件有一個名為plot
的方法可以用來生成圖表,如果選擇生成折線圖、餅圖、柱狀圖等,預設會使用Series物件的索引作為橫座標,使用Series物件的資料作為縱座標。
首先匯入matplotlib
中pyplot
模組並進行必要的配置。
import matplotlib.pyplot as plt
# 配置支援中文的非襯線字型(預設的字型無法顯示中文)
plt.rcParams['font.sans-serif'] = ['SimHei', ]
# 使用指定的中文字型時需要下面的配置來避免負號無法顯示
plt.rcParams['axes.unicode_minus'] = False
建立Series
物件並繪製對應的柱狀圖。
ser9 = pd.Series({'一季度': 400, '二季度': 520, '三季度': 180, '四季度': 380})
# 透過Series物件的plot方法繪圖(kind='bar'表示繪製柱狀圖)
ser9.plot(kind='bar', color=['r', 'g', 'b', 'y'])
# x軸的座標旋轉到0度(中文水平顯示)
plt.xticks(rotation=0)
# 在柱狀圖的柱子上繪製數字
for i in range(4):
plt.text(i, ser9[i] + 5, ser9[i], ha='center')
# 顯示影象
plt.show()
繪製反映每個季度佔比的餅圖。
# autopct引數可以配置在餅圖上顯示每塊餅的佔比
ser9.plot(kind='pie', autopct='%.1f%%')
# 設定y軸的標籤(顯示在餅圖左側的文字)
plt.ylabel('各季度佔比')
plt.show()