Skip to content

Latest commit

 

History

History
686 lines (514 loc) · 13.4 KB

70.Pandas的应用-1.md

File metadata and controls

686 lines (514 loc) · 13.4 KB

Pandas的應用-1

Pandas是Wes McKinney在2008年開發的一個強大的分析結構化資料的工具集。Pandas以NumPy為基礎(資料表示和運算),提供了用於資料處理的函式和方法,對資料分析和資料探勘提供了很好的支援;同時Pandas還可以跟資料視覺化工具Matplotlib很好的整合在一起,非常輕鬆愉快的實現資料的視覺化展示。

Pandas核心的資料型別是Series(資料系列)、DataFrame(資料表/資料框),分別用於處理一維和二維的資料,除此之外還有一個名為Index的型別及其子型別,它為SeriesDataFrame提供了索引功能。日常工作中以DataFrame使用最為廣泛,因為二維的資料本質就是一個有行有列的表格(想一想Excel電子表格和關係型資料庫中的二維表)。上述這些型別都提供了大量的處理資料的方法,資料分析師可以以此為基礎實現對資料的各種常規處理。

Series的應用

Pandas庫中的Series物件可以用來表示一維資料結構,跟陣列非常類似,但是多了一些額外的功能。Series的內部結構包含了兩個陣列,其中一個用來儲存資料,另一個用來儲存資料的索引。

建立Series物件

提示:在執行下面的程式碼之前,請先匯入pandas以及相關的庫檔案,具體的做法可以參考上一章。

方法1:透過列表或陣列建立Series物件

程式碼:

# data引數表示資料,index引數表示資料的索引(標籤)
# 如果沒有指定index屬性,預設使用數字索引
ser1 = pd.Series(data=[320, 180, 300, 405], index=['一季度', '二季度', '三季度', '四季度'])
ser1

輸出:

一季度    320
二季度    180
三季度    300
四季度    405
dtype: int64
方法2:透過字典建立Series物件。

程式碼:

# 字典中的鍵就是資料的索引(標籤),字典中的值就是資料
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,也可以選擇mergesortheapsort;如果存在空值,那麼可以用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物件的資料作為縱座標。

首先匯入matplotlibpyplot模組並進行必要的配置。

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()