天天看點

python資料清洗的方法有哪些_7步搞定資料清洗-Python資料清洗指南

作者:KOALA https://zhuanlan.zhihu.com/p/60241672

髒資料就是在實體上臨時存在過,但在邏輯上不存在的資料。

資料清洗是整個資料分析過程的第一步,就像做一道菜之前需要先擇菜洗菜一樣。資料分析師經常需要花費大量的時間來清洗資料或者轉換格式,這個工作甚至會占整個資料分析流程的80%左右的時間。

在這篇文章中,我嘗試簡單地歸納一下用Python來做資料清洗的7步過程,供大家參考。

一、資料預處理

一、資料預處理部署環境,導入分析包和資料#導入資料分析包

import pandas as pd

import numpy as np#導入csv資料

#dtype = str,最好讀取的時候都以字元串的形式讀入,不然可能會使資料失真

#比如一個0010008的編号可能會讀取成10008

fileNameStr = './Actual transactions from UK retailer.csv'

DataDF = pd.read_csv(fileNameStr,encoding = "ISO-8859-1",dtype = str)

# encoding = "ISO-8859-1" -- 用什麼解碼,一般會預設系統的編碼,如果是中文就用 "utf-8"

DataDF = pd.read_csv(fileNameStr,encoding = "utf-8",dtype = str)

2. 嘗試去了解這份資料集

我們可以通過對資料集提問來判斷這份資料能不能滿足解答我們的問題,資料是否幹淨需不需要進一步處理,問題包括但不限于:資料集多少資料?

包含了什麼字段?字段格式是什麼?

字段分别代表什麼意義

字段之間的關系是什麼?可以用做什麼分析?或者說能否滿足了對分析的要求?

有沒有缺失值;如果有的話,缺失值多不多?

現有資料裡面有沒有髒資料?尤其需要注意人工輸入的資料,經常會出現名稱寫錯,多輸入空格等等的情況

3. 下面我們就結合代碼來看一下資料#1 從宏觀一點的角度去看資料:檢視dataframe的資訊

DataDF.info()

也可以用這兩條來看:#1.1檢視每一列的資料類型

DataDF.dtypes

#1.2有多少行,多少列

DataDF.shape# 2.檢查缺失資料

# 如果你要檢查每列缺失資料的數量,使用下列代碼是最快的方法。

# 可以讓你更好地了解哪些列缺失的資料更多,進而确定怎麼進行下一步的資料清洗和分析操作。

DataDF.isnull().sum().sort_values(ascending=False)# 3.是抽出一部分資料來,人工直覺地了解資料的意義,盡可能地發現一些問題

DataDF.head()

可以看到:

1)Country和UnitPrice都出現了NaN值,需要去掉

2)InvoiceDate的時間出現具體時分,可以删去

3)Description大機率是人工填寫的資料,一般都會有比較多格式問題。

猜測會存在有标點符号摻雜/大小寫不一緻等問題,是以進一步這些人工填寫資料的去重項拎出來研究一下# 檢視這個商品名稱的去重項

DataDF['Description'].unique()# 設定輸出全部的内容

# threshold就是設定超過了多少條,就會呈現省略

#(比如threshold=10的意思是超過10條就會省略)

np.set_printoptions(threshold=np.inf)

發現有很多空格的問題

根據第一步資料預處理後,整理一下該資料集有下列問題需要處理:

1)調整資料類型:由于一開始用到了str來導入,打算後期再更換格式,需要調整資料類型。

2)修改列名:該資料的名稱不易于了解,需要改列名

3)選擇部分子集:因為有部分列在資料分析中不需要用到

4)可能存在邏輯問題需要篩選:比如Unit Price為負

5)格式一緻化:Description可能會存在有标點符号摻雜/大小寫不一緻/空格重複出現等問題

6)消滅空值:CustomerID、Description、Country和UnitPrice都出現了NaN值,需要去掉

于是下面就開始後續的資料清洗6步

二、調整資料類型

資料類型調整前#字元串轉換為數值(整型)

DataDF['Quantity'] = DataDF['Quantity'].astype('int')

#字元串轉換為數值(浮點型)

DataDF['UnitPrice'] = DataDF['UnitPrice'].astype('float')

日期調整前(為求簡便這裡用已經剔除分秒,剔除的辦法後面在格式一緻化的空格分割再詳細說)#資料類型轉換:字元串轉換為日期

#errors='coerce' 如果原始資料不符合日期的格式,轉換後的值為空值NaT

DataDF.loc[:,'InvoiceDate']=pd.to_datetime(DataDF.loc[:,'InvoiceDate'],

format='%d/%m/%Y',

errors='coerce')

#!!⚠️ format 是你[原始資料]中日期的格式

%y 兩位數的年份表示(00-99)

%Y 四位數的年份表示(000-9999)

%m 月份(01-12)

%d 月内中的一天(0-31)

%H 24小時制小時數(0-23)

%I 12小時制小時數(01-12)

%M 分鐘數(00-59)

%S 秒(00-59)

日期類型調整後

資料類型調整完畢

三、修改列名

修改前#建立字典字典:舊列名和新列名對應關系

colNameDict = {'InvolceDate':'SaleDate','StockCode':'StockNo'}

#!! ⚠️一定要舊列名放在冒号前

#每組對應關系以[逗号]隔開

salesDf.rename(columns = colNameDict,inplace=True)

修改後

四、選擇部分子集

這是一個8列*541909行的資料集。#選擇子集,選擇其中一列

subDataDF1=DataDF["InvoiceDate"]#選擇子集,選擇其中兩列

subDataDF1=DataDF[["InvoiceDate","UnitPrice"]]

利用切片篩選資料功能 df.loc

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.loc.html#pandas.DataFrame.loc

loc這個代碼有點像Excel裡面的滑鼠左鍵,可以随意拉動你需要的資料進行切片。

以逗号作為隔開的界限,左邊為index,右邊為columnsubDataDF1=DataDF.loc[:,"InvoiceDate"]

subDataDF1

#單一個冒号意味着不作限制的全選subDataDF2=DataDF.loc[0:9,:]

subDataDF2subDataDF3=DataDF.loc[1:9,"StockCode":"CustomerID"]

subDataDF3

五、邏輯問題需要篩選

還是Dataframe.loc這個函數的知識點。

由于loc還可以判斷條件是否為TrueDataDF.loc[:,'UnitPrice']>0

一般來說價格不能為負,是以從邏輯上來說如果價格是小于0的資料應該予以篩出#删除異常值:通過條件判斷篩選出資料

#查詢條件

querySer=DataDF.loc[:,'Quantity']>0

#應用查詢條件

print('删除異常值前:',DataDF.shape)

DataDF=DataDF.loc[querySer,:]

print('删除異常值後:',DataDF.shape)

六、格式一緻化大小寫/去除空格

将我們資料中所有的Descrption改成大寫:DataDF['Description']= DataDF['Description'].str.upper()

類似的代碼還有 字元串修改方法:str().

upper()

lower()

title()

lstrip()

strip()

DataDF['Description']= DataDF['Description'].str.strip()

2. 去除字元串符号 去亂碼

3. 空格分割#定義函數:分割InvoiceDate,擷取InvoiceDate

#輸入:timeColSer InvoiceDate這一列,是個Series資料類型

#輸出:分割後的時間,傳回也是個Series資料類型

def splitSaletime(timeColSer):

timeList=[]

for value in timeColSer:

#例如2018/01/01 12:50,分割後為:2018-01-01

dateStr=value.split(' ')[0]

timeList.append(dateStr)

#将清單轉行為一維資料Series類型

timeSer=pd.Series(timeList)

return timeSer

最後再指派回去DataDF.loc[:,'InvoiceDate']=splitSaletime(DataDF.loc[:,'InvoiceDate'])

七、處理缺失值

python缺失值有3種:

1)Python内置的None值

2)在pandas中,将缺失值表示為NA,表示不可用not available。

3)對于數值資料,pandas使用浮點值NaN(Not a Number)表示缺失資料。後面出來資料,如果遇到錯誤:說什麼float錯誤,那就是有缺失值,需要處理掉

是以,缺失值有3種:None,NA,NaN

那None和NaN有什麼差別呢:

None是Python的一種資料類型,

NaN是浮點類型

兩個都用作空值

1、去除缺失值# 再一次提醒檢查缺失資料

DataDF.isnull().sum().sort_values(ascending=False)

去除缺失值的知識點:

DataFrame.dropna

DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)# 預設(axis=0)是逢空值剔除整行,設定關鍵字參數axis=1表示逢空值去掉整列

# 'any'如果一行(或一列)裡任何一個資料有任何出現Nan就去掉整行,

‘all’一行(或列)每一個資料都是Nan才去掉這整行

DataDF.dropna(how='any')

DataDF.dropna(how='all')

# 更精細的thresh參數,它表示留下此行(或列)時,要求有多少[非缺失值]

DataDF.dropna(thresh = 6 )

2、填充缺失内容:某些缺失值可以進行填充,方法有以下四種:

1) 以業務知識或經驗推測(預設值)填充缺失值

2) 以同一名額的計算結果(均值、中位數、衆數等)填充缺失值

3) 用相鄰值填充缺失值

4) 以不同名額的計算結果填充缺失值

去除缺失值的知識點:

DataFrame.fillna

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.fillna.html#pandas.DataFrame.fillna

1) 用預設值填充- df.fillna(' ')

我們應該去掉那些不友好的 NaN 值。但是,我們應該用什麼值替換呢?這個時候可能要結合你對這個資料集的了解,看填充什麼資料才是比較合适,以下是一下常用的方法。

在這個資料集中,我們大緻判斷CustomerID如果是不太重要的,就我們可以用使用""空字元串或其他預設值。DataDF.Country= DataDF.Country.fillna('Not Given')

上面,我們就将“country”整個列使用“”空字元串替換了,或者,我們也可以輕易地使用“Not Given”這樣的預設值進行替換。

如果想了解更多 fillna() 的詳細資訊參考 pandas.DataFrame.fillna

pandas.pydata.org

2) 以同一名額的計算結果(均值、中位數、衆數等)填充缺失值

平均值- df.fillna(df.mean())

使用數字類型的資料有可能可以通過這樣的方法來去減少錯誤。

比如,這個案例裡面的價格。如果用0或者"Not Given"等來去填充都不太合适,但這個大概的價格是可以根據其他資料估算出來的。DataDF.UnitPrice = DataDF.UnitPrice.fillna(DataDF.UnitPrice.mean())

3)除此,還有一種常見的方法,就是用相鄰的值進行填充,

這在時間序列分析中相當常見,用前面相鄰的值向後填充,也可以用後面相鄰的值向前填充。print(DataDF)

print(DataDF.UnitPrice.fillna(method='ffill')) # 前向後填充

print(DataDF.UnitPrice.fillna(method='bfill')) # 後向前填充

填充後

4) 以不同名額的計算結果填充缺失值

關于這種方法年齡字段缺失,但是有屏蔽後六位的身份證号可以推算具體的年齡是多少。