07>>>數據清洗


07.數據清洗

 

數據清洗概念

  之前已經講過,數據分析的過程是這樣的。

1.明確需求
2.數據采集
3.數據清洗
4.數據分析
5.數據報告+數據可視化

  之前我們學習的一系列python模塊,比如BeautifulSoup、Xpath、selenium等模塊,都是屬於數據清洗的范疇;matplotlib模塊屬於數據可視化模塊。numpy和pandas模塊我們側重於學習了理論部分,接下來我們就要學習如何在實際工作中使用它們了。

  干巴巴的理論不太好理解,我們還是打個比方來幫助記憶,如果把數據分析比作做菜:

數據分析過程    →    做菜過程
明確需求            明確做什么菜品
數據采集            去市場買菜
數據清洗            洗菜切菜配菜
數據分析            下鍋炒菜
數據報告+數據可視化   拍照發朋友圈+吃菜

 

什么是數據清洗?

  數據清洗的定義:從記錄表、表格、數據庫中檢測、糾正或刪除損壞或不准確記錄的過程。

  換個俏皮的說法,數據清洗就是把臟數據變為干凈的數據的過程。

  臟數據:沒有經過處理的自身含有一定問題的數據(殘缺數據、錯誤數據、重復數據、不符合規則的數據)。

   干凈數據:經過處理的完全符合規范要求的數據(可以直接帶入模型)。

數據清洗的常用方法

1.讀取外部數據

pd.read_csv
pd.read_excel
pd.read_sql
pd.read_html

2.數據概覽

index
columns
head
tail
shape
describe
info
dtype

  除了info比較眼生,這些內容都是之前在pandas模塊的DataFrame數據類型中就學習過的參數。

3.簡單處理

移除首尾空格
大小寫轉換

4.重復值處理

duplicated()  # 查看是否含有重復數據
drop_duplicats()  # 刪除重復數據

MySQL中的操作

  我們來回憶一下,MySQL中如何快速判斷某列是否含有重復的數據?

create database db1;
create table t1(id int,name varchar(32),pwd int);
insert into t1 values(1,'joe',123),(2,'simon',321),(3,'frank',222),(4,'jerry',111),(5,'eddie',222),(6,'eddie',333);

思路:

select count(name) from t1;  # 統計表t1中name字段的數據量

  如果只單純給name字段計數的話,它只會給出name字段所有數據的數量。

  所以我們首先要進行去重操作,然后統計字段去重后的數據。將得到的計數和原先未去重的計數相一比較,立馬就能知道有沒有重復的數據了。

select count(distinct(name)) from t1;  # 將name字段的數據去重之后再計數

   若兩者數字相同,表示name列沒有重復的數據,不同則表示含有重復的數據。

5.缺失數值處理

刪除缺失值
填充缺失值
    均值填充法
    向前填充/向后填充(原理,視頻03)
    模型填補法,如隨機森林
    ……

  向前填充即是指缺失值選用前面一個值進行填充,向后填充即是指缺失值選用后面一個值進行填充。

   模型填補法這里暫且不展開講,混個眼熟即可。

6.異常值處理

刪除異常值
作為缺失值處理
修正異常值(同樣是當做缺失值處理)
    平均值修正、蓋帽法修正

7.文本字符串處理

切割
篩選
……

8.時間格式處理

Y  #
m  #
d  #
H  #
M  #
S  #

  其中許多內容都是曾經學習過的知識點,具體用法可以參考過去的博客。

  在整套數據清洗流程中,第3~第8步沒有固定的順序,可以根據需要隨意調整操作順序。前期不熟練時可以按序號來。

 

數據清洗實戰案例

  接下來我們就通過一個實際案例來看看數據清洗應該怎么做,同時這也是對之前學的個方面內容的一個全面回顧。

旅游數據的清洗

  首先啟動anaconda,等到載入完后運行jupyter notebook。新建文件夾並且重命名便於辨識。放入數據資料,新建python3文件。准備工作都完成后我們可以進行編程了。

  首先還是雷打不動地載入需要用到的模塊。

# 導入三劍客
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

1.讀取數據

data = pd.read_csv(r'qunar_freetrip.csv')

2.數據概覽

data.index  # 查看行數
data.columns  # 查看列字段
data.shape  # 查看行數和列數
data.head()  # 查看頭幾行數據
data.tail()  # 查看尾幾行數據
data.dtypes  # 查看字段類型
data.describe()  # 簡單的數據統計
data.describe(include='all')  # include參數可以指定計算的類型,all表示不論數據類型所有字段都進行數據統計(一般不加)
data.info()  # 既可以查看每個列的數據類型,還可以查看缺失數據量

  data.info是個挺有意思的語句,不光列出了字段的名稱,還列出了每個字段的總數、缺失數據數量、字段數據類型。

3.簡單處理

1.將Unnamed: 0列刪除

data.drop(columns=['Unnamed: 0'],inplace=True)  # 既可以刪列數據也可以刪行數據

2.列字段處理

data['列字段']  # 獲取指定列字段的數據
eg:
data['目的地']  # 報錯

  報錯?但是語句沒問題啊。

  其實這里是有個小陷阱,如果觀察不仔細很容易忽略。

data.columns  # 查看列字段

  有些列字段中帶有空格,所以單寫中文沒法獲取到數據。

  所以應該先移除列字段空格。

new_columns = []  # 定義一個空列表
for col in data.columns:  # 循環獲取列字段名
    new_columns.append(col.strip())  # 將去除空格后的列字段名加入到空列表中
data.columns = new_columns  # 修改原列字段

   這里還可以做優化,用列表生成的方式就能用一行代碼解決。

data.columns = [col.strip() for col in data.columns]
data.columns = new_columns

  無論用哪種方式,改完后都可以正常索引獲取數據了。

data['目的地']  # 可以正常獲取

4.重復值處理

  首先,查看是否含有重復數據。

data.duplicated().sum()  # 查看重復數據的數量
data[data.duplicated()]  # 查看重復數據

  其中有100條重復數據。

# 直接刪除重復數據
data.drop_duplicates(inplace=True)
# 驗證是否成功
data.duplicated().sum()  # 0
data.shape  # (5000, 13)
# 刪除重復數據后將引發行標簽問題(行標簽並不會重新排序)
data.tail()

  針對行標簽是否需要重新排序,取決於業務需要,一般情況下可以不重排。

data.reset_index(inplace=True)  # 重置行標簽,重置后會默認保留原來的行標簽
data.drop(columns=['index'],inplace=True)  # 刪除原來的行標簽

  重置行標簽另有一種更簡便的方法(支持自定義起始數字,推薦)

data.index = range(0,df.shape[0])

5.異常值處理

1.利用快速統計大致篩選出可能有異常值的列字段

data.describe()

  節省這一列看起來很不正常,統計下來的總和居然比價格還要多出幾塊錢來。

  可以利用公式求證我們的猜想。

公式計算:(列數據-列數據均值)/列數據標准差,如果值大於3就是有異常的。
sd = (((data['價格'] - data['價格'].mean()) / data['價格'].std())>3).sum()  # 有可能是負數

  得到的結果可能是負數,所以這里需要用到絕對值。

sd_abs = abs(((data['價格'] - data['價格'].mean()) / data['價格'].std())>3).sum()
data[sd_abs]

2.同理驗證節省是否有異常

sd2_abs = abs(((data['節省'] - data['節省'].mean()) / data['節省'].std())>3).sum()  # 按照公式計算確實存在異常,但可能是由於促銷、引流等因素導致的,針對這類數據可以保留

3.驗證節省大於價格的

data[data['節省'] > data['價格']]

4.刪除價格和節省都有異常的數據

pd.concat(data[])  # 合並表
data.drop(index=del_index,inplace=True)  # 操作完后行標簽又變了,需要的話還是要調整

6.缺失數據處理

# 查看缺失數據的方式
data.isnull().sum()  # 求每個列字段中缺失數據的數量
data.info()  # 也可以驗證

1.修改出發地缺失數據

res = data[data['出發地'].isnull()]  # 篩選出出發地為缺失值的數據

  缺失數據項有時可能存在於其他列數據中。

  接下來就是取值了。

res['路線名'].values  # 從路線名字段中取值

  針對本案例有多種獲取城市名的方式。

# 1.字符串切片(適用性太窄,局限性太大,不推薦)
d1[0:2]
# 2.字符串切割(可以)
d1.split('-')[0]
# 3.正則表達式
import re
re.findall('(.*?)-',d2)
# 可用列表表達式來完成
data.loc[data.出發地.isnull(),'出發地'] = [i.split('-')[0] for i in data.loc[data.出發地.isnull(),'路線名'].values]
# 驗證是否還有缺失數據
data[data['出發地'].isnull()]

2.修改目的地缺失數據

# 篩選出目的地為缺失值的數據
res = data[data['目的地'].isnull()]
res
# 從路線名字段中取值
data.loc[data.目的地.isnull(),'路線名'].values
d3 = '深圳-大連3天2晚 | 入住大連黃金山大酒店 + 南方航空/東海往返機票'
# 正則篩選出需要的數據
re.findall('-(.*?)\d',d3)
# 三元表達式整合
data.loc[data.目的地.isnull(),'目的地'] = [re.findalll('-(.*?)\d',i) for i in data.loc[data.目的地.isnull(),'路線名'].values]
# 驗證是否還有缺失數據
data[data['目的地'].isnull()]

3.修改價格缺失數據

round(data['價格'].mean(),1)  #求價格均值,保留一位小數
data['價格'].fillna(round(data['價格'].mean(),1),inplace=True)  # 用價格平均值填充入缺失數據
data[data['價格'].isnull()]  # 驗證是否還有缺失數據

4.修改節省缺失數據

round(data['節省'].mean(),1)  #求節省均值,保留一位小數
data['節省'].fillna(round(data['節省'].mean(),1),inplace=True)  # 用節省平均值填充入缺失數據
data[data['節省'].isnull()]  # 驗證是否還有缺失數據

  如此一來,例題的數據清洗步驟就完成了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM