0. 序言
在做資料分析之前,我們首先要明確資料分析的目標,然後 應用資料分析的思維,對目標進行細分,再採取相應的行動。
我們可以把資料分析細分為以下 8 個步驟:
(1)讀取
(2) 清洗
(3) 操作
(4) 轉換
(5) 整理
(6) 分析
(7) 展現
(8)報告
在《 如何用 Python 讀取資料? 》這篇文章中,我們學習了從 5 種不同的地方讀取資料的方法,接下來,我們將利用其中的一種方法, 從 Excel 檔案中讀取原始資料,然後利 用 Python 對它進行清洗。
下面我們用一副待清洗的撲克牌作為示例,假設它儲存在程式碼檔案相同的目錄下,在 Jupyter Lab 環境中執行以下程式碼:
import numpy as npimport pandas as pd# 設定最多顯示 10 行pd.set_option('max_rows', 10)# 從 Excel 檔案中讀取原始資料df = pd.read_excel( '待清洗的撲克牌資料集.xlsx')df
返回結果如下:
這幅待清洗的撲克牌資料集,有一些異常情況,包括:大小王的花色是缺失的,有兩張重複的黑桃:spades: A,還有一張異常的 黑桃 :spades: 30。
1. 如何查詢異常?
在正式開始清洗資料之前,往往需要先把異常資料找出來,觀察異常資料的特徵,然後再決定清洗的方法。
# 查詢「花色」缺失的行df[df.花色.isnull()]
# 查詢完全重複的行df[df.duplicated()]
# 查詢某一列重複的行df
# 查詢牌面的所有唯一值df.牌面.unique()
返回結果:
array(['大王', '小王', 'A', '30', 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 2, 3], dtype=object)
根據常識可以判斷,牌面為 30 的是異常值。
# 查詢「牌面」包含 30 的異常值df[df.牌面.isin(['30'])]
# 查詢王牌,模糊匹配df[df.牌面.str.contains( '王', na=False)]
# 查詢編號在 1 到 5 之間的行df[df.編號.between(1, 5)]
查詢某個區間,也可以用邏輯運算的方法來實現:
# 查詢編號在 1 到 5 之間的行df[(df.編號 >= 1) & (df.編號 <= 5)]
其中「 & 」代表必須同時滿足兩邊的條件,也就是「且」的意思。
還可以用下面等價的方法:
# 查詢編號在 1 到 5 之間的行df[~((df.編號 < 1) | (df.編號 > 5))]
其中「 | 」代表兩邊的條件滿足一個即可,也就是「或」的意思,「 ~ 」代表取反,也就是「非」的意思。
2. 如何排除重複?
使用 drop_duplicates() 函式,在排除重複之後,會得到一個新的資料框。
# 排除完全重複的行,預設保留第一行df.drop_duplicates()
返回結果如下:
如果想要改變原來的資料框,有兩種方法,一種方法,是增加 inplace 引數:
# 排除重複後直接替換原來的資料框df.drop_duplicates( inplace=True)
另一種方法,是把得到的結果,重新賦值給原來的資料框:
# 排除重複後,重新賦值給原來的資料框df = df.drop_duplicates()
如果想要按某一列排除重複的資料,那麼指定相應的列名即可。
# 按某一列排除重複,預設保留第一行df.drop_duplicates(['花色'])
如果想要保留重複的最後一行,那麼需要指定 keep 引數。
# 按某一列排除重複,並保留最後一行df.drop_duplicates( ['花色'], keep='last')
從上面兩個返回結果的編號可以看出,不同方法的差異情況。
3. 如何刪除缺失?
使用 dropna() 函式,預設刪除包含缺失的行。為了更加簡單易懂,我們用撲克牌中不重複的花色作為示例。
# 不重複的花色color = df.drop_duplicates( ['花色'])color
# 刪除包含缺失值的行color.dropna()
如果想要刪除整行全部為空的行,那麼需要指定 how 引數。
# 刪除全部為空的行color.dropna(how='all')
如果想要刪除包含缺失值的列,那麼需要指定 axis 引數。
# 刪除包含缺失值的列color.dropna(axis=1)
可以看到,包含缺失值的「花色」這一列被刪除了。
4. 如何補全缺失?
使用 fillna() 函式,可以將缺失值填充為我們指定的值。
# 補全缺失值color.fillna('Joker')
可以看到,原來的 NaN 被填充為 Joker,在實際工作的應用中,通常填充為 0,也就是說, fillna(0) 是比較常見的用法。
如果想要使用臨近的值來填充,那麼需要指定 method 引數,例如:
# 用後面的值填充color.fillna(method='bfill')
可以看到,原來第一行的 NaN 替換成了第二行的「黑桃:spades:」。
其中 method 還有一些其他的可選引數,詳情可以檢視相關的幫助文件。
還有一種按字典填充的方法。為了讓下面的演示更加直觀易懂,我們先把索引為 2 的牌面設定為缺失值:
# 為了演示,先指定一個缺失值color.loc[2, '牌面'] = np.nancolor
# 按列自定義補全缺失值color.fillna( {'花色': 0, '牌面': 1})
可以看出,不同列的缺失值,可以填充為不同的值,花色這一列填充為 0,牌面這一列填充為 1,我在圖中分別用紅色的方框標記出來了。
5. 應用案例
下面 我們用 Python 程式碼,把這幅待清洗的撲克牌資料集,變成一副正常的撲克牌資料。
import numpy as npimport pandas as pd# 設定最多顯示 10 行pd.set_option('max_rows', 10)# 從 Excel 檔案中讀取原始資料df = pd.read_excel( '待清洗的撲克牌資料集.xlsx')# 補全缺失值df = df.fillna('Joker')# 排除重複值df = df.drop_duplicates()# 修改異常值df.loc[4, '牌面'] = 3# 增加一張缺少的牌df = df.append( {'編號': 4, '花色': '黑桃', '牌面': 2}, ignore_index=True)# 按編號排序df = df.sort_values('編號')# 重置索引df = df.reset_index()# 刪除多餘的列df = df.drop( ['index'], axis=1)# 把清洗好的資料儲存到 Excel 檔案df.to_excel( '完成清洗的撲克牌資料.xlsx', index=False)df
返回結果如下:
可以看到,我們已經成功地把它變成了一副正常的撲克牌資料。
6. 小結
我們簡單回顧一下本文的主要內容,首先,我們從宏觀層面介紹了資料分析的 8 個步驟,然後用一副待清洗的撲克牌資料集作為示例,從讀取資料,到查詢異常,再到排除重複、刪除缺失和補全缺失,最後,我們用一個案例, 完整 演示了清洗資料的過程。