數據清洗之數據預處理
摩托車的銷售情況數據
- Condition:摩托車新舊情況(new:新的 和used:使用過的)
- Condition_Desc:對當前狀況的描述
- Price:價格
- Location:發獲地址
- Model_Year:購買年份
- Mileage:里程
- Exterior_Color:車的顏色
- Make:制造商(牌子)
- Warranty:保修
- Model:類型
- Sub_Model:車輛類型
- Type:種類
- Vehicle_Title:車輛主題
- OBO:車輛儀表盤
- Watch_Count:表數
- N_Reviews:評測次數
- Seller_Status:賣家身份
- Auction:拍賣(Ture或者False)
- Buy_Now:現買
- Bid_Count:出價計數
In [ ]:
import numpy as np import pandas as pd import os
In [ ]:
os.chdir(r'F:\CSDN\課程內容\代碼和數據')
In [ ]:
df = pd.read_csv('MotorcycleData.csv',encoding = 'gbk',na_values='Na')
na_values='Na' 對所有的空字符串做缺失值填充
na_values='used' 對所有的‘used’的數據寫成缺失值
1. 重復值處理
In [ ]:
df.head(5)
- 對價格和里程數數據進行處理
In [ ]:
# 自定義一個函數
def f(x): if '$' in str(x): x = str(x).strip('$') # 去除 x = str(x).replace(',','') # 替換 else: x = str(x).replace(',','') return float(x)
In [ ]:
df['Price'] = df['Price'] .apply(f)
In [ ]:
df['Mileage'] = df['Mileage'].apply(f)
In [ ]:
print ('數據集是否存在重復觀測: \n', any(df.duplicated()))
In [ ]:
df[df.duplicated()] #查看那些數據重復(全部)
In [ ]:
np.sum(df.duplicated()) #計算重復數量
In [ ]:
df.drop_duplicates() #刪除所有變量都重復的行, 注意沒有加inplace = True,只會是視圖上刪除,只有加了才對原始數據改動
In [ ]:
df.drop_duplicates(subset= ['Condition','Condition_Desc','Price','Location'],inplace=True) #按照兩個變量重復 來 來去重
In [ ]:
df.info()
2. 缺失值處理
In [ ]:
df.apply(lambda x: sum(x.isnull())/len(x),axis= 0) #缺失比例,超過90%或95%就可以扔了
In [ ]:
#刪除法
df.dropna() #直接刪除法
In [ ]:
df.dropna(how='any',axis = 1 ) #只要有缺失,就刪除這一列
df.dropna(how='all',axis = 1 ) #只有全部缺失,才刪除這一列
In [ ]:
df.dropna(how='any',axis = 0) #只要有缺失,就刪除這一行,等價於df.dropna()
- axis = 0 或者 1代表的函數在數據集作用的方向,0代表沿着行的方向,1代表沿着列的方向
In [ ]:
df.dropna(axis = 0,how='any',subset=['Condition','Price','Mileage']) # 1代表列,0代表行,只要有缺失,就刪除這一行,基於三個變量
在數據分析中,實際上大部分時候都是按照行來進行刪除的,很少會基於列來進行刪除 列代表的是變量,是否刪除刪除列很多時候主要取決於缺失比例
使用替換法進行缺失值的填補
- 替換法
In [ ]:
df.head(10)
In [ ]:
df.Mileage.fillna(df.Mileage.mean()) # 年齡這里列 用均值填補
In [ ]:
df.Mileage.fillna(df.Mileage.median()) #中位數填補
In [ ]:
df[df['Exterior_Color'].isnull()]
In [ ]:
df.Exterior_Color.fillna(df.Exterior_Color.mode()[0]) #眾數填補mode()[0],眾數可能有好幾個,后面表示取第一個
In [ ]:
df.fillna(20) # 所有缺失用20填補
In [ ]:
# 車的顏色使用眾數,里程樹使用均值
df.fillna(value = {'Exterior_Color':df.Exterior_Color.mode()[0],'Mileage':df.Mileage.mean()})
這里還是沒有加inplace=True,所以數據本身沒變,只是視圖變化了
In [ ]:
df['Exterior_Color'].fillna(method='ffill') #前向填補
In [ ]:
df['Exterior_Color'].fillna(method='bfill') #后向填補
3.異常值處理
df.Price和df['Price']的作用應該是一樣的
- 異常值檢測可以使用均值的2倍標准差范圍,也可以使用上下4分位數差方法
In [ ]:
# 判斷年齡有什么異常值
# 剔除戶主姓名,戶主身份證號和年齡有缺失的樣本 df.dropna(axis = 0,how='any',subset=['戶主姓名','戶主身份證號','age'],inplace = True) #1代表列,0代表行,只要有缺失,就刪除這一行,基於三個變量
In [ ]:
# 異常值檢測之標准差法
xbar = df.Price.mean() 均值 xstd = df.Price.std() 標准差 print('標准差法異常值上限檢測:\n',any(df.Price> xbar + 2.5 * xstd)) print('標准差法異常值下限檢測:\n',any(df.Price< xbar - 2.5 * xstd))
In [ ]:
# 異常值檢測之箱線圖法
Q1 = df.Price.quantile(q = 0.25) 取25%為分位數 Q3 = df.Price.quantile(q = 0.75) IQR = Q3 - Q1 分位差
In [ ]:
print('箱線圖法異常值上限檢測:\n',any(df.Price > Q3 + 1.5 * IQR)) print('箱線圖法異常值下限檢測:\n',any(df.Price < Q1 - 1.5 * IQR))
In [ ]:
df.Price.describe()# 對價格進行描述性統計
In [ ]:
import matplotlib.pyplot as plt %matplotlib inline
In [ ]:
df.Price.plot(kind ='box')
In [ ]:
# 導入繪圖模塊
import matplotlib.pyplot as plt # 設置繪圖風格 plt.style.use('seaborn') # 繪制直方圖(30條柱子,密度以概率密度) df.Price.plot(kind = 'hist', bins = 30, density = True) # 繪制核密度圖 df.Price.plot(kind = 'kde') # 圖形展現 plt.show()
In [ ]:
# 用99分位數和1分位數替換
#計算P1和P99 P1 =df.Price.quantile(0.01); P99 = df.Price.quantile(0.99)
#先創建一個新變量,進行賦值,然后將滿足條件的數據進行替換
df['Price_new'] = df['Price'] df.loc[df['Price'] > P99,'Price_new'] = P99 df.loc[df['Price'] < P1,'Price_new'] = P1
回憶:#注意loc是標簽 #注意iloc是位置
In [ ]:
df[['Price','Price_new']].describe()
4.數據離散化
-
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False)
-
參數:
- x,類array對象,且必須為一維,待切割的原形式
- bins, 整數、序列尺度、或間隔索引。如果bins是一個整數,它定義了x寬度范圍內的等寬面元數量,但是在這種情況下,x的范圍在每個邊上被延長1%,以保證包括x的最小值或最大值。如果bin是序列,它定義了允許非均勻bin寬度的bin邊緣。在這種情況下沒有x的范圍的擴展。
- right,布爾值。是否是左開右閉區間,right=True,左開右閉,right=False,左閉右開
- labels,用作結果箱的標簽。必須與結果箱相同長度。如果FALSE,只返回整數指標面元。
- retbins,布爾值。是否返回面元
- precision,整數。返回面元的小數點幾位
- include_lowest,布爾值。第一個區間的左端點是否包含
In [ ]:
df.head(5)
In [ ]:
df['Price_bin'] = pd.cut(df['Price_new'],5,labels=range(5))
#切分五大類,把這五份分別取0~5的標簽 df['Price_bin'].hist()
- 自定義分段標准和標簽
In [ ]:
df['Price_new'].describe()
In [ ]:
w = [100,1000,5000,10000,20000,50000]
In [ ]:
df['Price_bin'] = pd.cut(df['Price_new'], bins =w,labels=['低','便宜','划算','中等','高'],right=False)
In [ ]:
df['Price_bin'].value_counts()
cut的樣本是不平均的
q cu t的樣本划分下來基本是平均的
- pandas.qcut(x, q, labels=None, retbins=False, precision=3, duplicates=’raise’)
- 參數:
- x
- q,整數或分位數組成的數組。
- q, 整數 或分位數數組 整數比如 4 代表 按照4分位數 進行切割
- labels, 用作結果箱的標簽。必須與結果箱相同長度。如果FALSE,只返回整數指標面元。
- 原理都是基於分位數來進行離散化
In [ ]:
k = 5 w = [1.0*i/k for i in range(k+1)] w
這里w的作用就是分位
值為[0.0,0.2,0.4,0.6,0.8,1.0]
也就是“等頻”
In [ ]:等頻分段
df['Price_bin'] = pd.qcut(df['Price_new'],w,labels=range(k))
# 這里的w賦值的是q這個變量
In [ ]:
df['Price_bin'].hist()
- 或者先計算分位數的值
In [ ]:
k = 5 w1 = df['Price_new'].quantile([1.0*i/k for i in range(k+1)])#先計算分位數,在進行分段 w1[0] = w1[0]* 0.95 # 最小值縮小一點 w[-1] = w1[1]* 1.05 # 將最大值增大一點, 目的是為了確保數據在這個范圍內
In [ ]:
w1
In [ ]:
df['Price_bin'] = pd.cut(df['Price_new'],w1,labels=range(k)) df['Price_bin'].hist()
#在上面這個例子中,有兩種分的方法,其中w啊是先划分一個等頻段,w1是先計算了數據本身的等頻區間。
