数据清洗
数据清洗, 是整个数据分析过程中不可缺少的一个环节,其结果质量直接关系到模型效果和最终结论。在实际操作中,数据清洗通常会占据分析过程的50%—80%的时间。
去除重复数据
在获取到的数据中,我们发现会有重复数据。我们使用Pandas 提供的方法 duplicated 和 drop_duplicates来去重。
1 2 3 4 5 6 7 8 9 10 11 12 13
| sample = pd.DataFrame({'id':[1,1,1,3,4,5], 'name':['Bob','Bob','Mark','Miki','Sully','Rose'], 'score':[99,99,87,77,77,np.nan], 'group':[1,1,1,2,1,2]}) sample Out[85]: id name score group 0 1 Bob 99.0 1 1 1 Bob 99.0 1 2 1 Mark 87.0 1 3 3 Miki 77.0 2 4 4 Sully 77.0 1 5 5 Rose NaN 2
|
查找重复数据:
1 2 3 4
| sample[sample.duplicated()] Out[86]: id name score group 1 1 Bob 99.0 1
|
需要去重时:
1 2 3 4 5 6 7 8
| sample.drop_duplicates() Out[87]: id name score group 0 1 Bob 99.0 1 2 1 Mark 87.0 1 3 3 Miki 77.0 2 4 4 Sully 77.0 1 5 5 Rose NaN 2
|
按列去重时,需要加入列索引:
1 2 3 4 5 6 7
| sample.drop_duplicates('id') Out[88]: id name score group 0 1 Bob 99.0 1 3 3 Miki 77.0 2 4 4 Sully 77.0 1 5 5 Rose NaN 2
|
缺失值处理
在数据挖掘中,面对数据中存在缺失值时,我们一般采取以下几种办法:
- 缺失值较多的特征处理
当缺失值处于20%~80%,每个缺失值可以生成一个指示哑变量,参与后续的建模。
2.缺失较少时
首先需要根据业务理解处理缺失值,弄清楚缺失值产生的原因,是故意缺失还是随机缺失。可以依靠业务经验进行填补。连续变量可以使用均值或中位数进行填补。
1 2 3 4
| # 将所有行用各自的均值填充 df.fillna(df.mean()) # 将所有行用各自的均值填充 df.fillna(df.mean()['collum_name])
|
1 2 3 4 5
| # 用前一个数据替代NaN df.fillnan(method="pad")
# 与pad相反,bfill表示用后一个数据代替NaN df.fillna(method=)
|
1 2
| # 插值法就是通过两点(x0,y0),(x1,y1)估计中间点的值 df.interpolate()
|
- 查看数据值缺失情况,我们可有构造一个lambda 函数来查看缺失值。
1 2 3 4 5 6 7 8 9 10 11 12
| sample = pd.DataFrame({'id':[1,1,1,3,4,np.nan], 'name':['Bob','Bob','Mark','Miki','Sully',np.nan], 'score':[99,99,87,77,77,np.nan], 'group':[1,1,1,2,1,np.nan]}) sample sample.apply(lambda col:sum(col.isnull())/col.size) Out[91]: id 0.166667 name 0.166667 score 0.166667 group 0.166667 dtype: float64
|
已指定值填补
均值
1 2 3 4 5 6 7 8 9
| sample.score.fillna(sample.score.mean()) Out[93]: 0 99.0 1 99.0 2 87.0 3 77.0 4 77.0 5 87.8 Name: score, dtype: float64
|
中位数
1 2 3 4 5 6 7 8 9
| sample.score.fillna(sample.score.median()) Out[94]: 0 99.0 1 99.0 2 87.0 3 77.0 4 77.0 5 87.0 Name: score, dtype: float64
|
缺失值指示变量
Panda DataFrame 对象可以直接调用方法isnull 产生缺失值指示变量,例如产生score变量的缺失值变量:
1 2 3 4 5 6 7 8 9 10
| sample.score.isnull() Out[95]: 0 False 1 False 2 False 3 False 4 False 5 True Name: score, dtype: bool
|
若想转化为数据0,1型指示变量,可以使用apply方法,int表示将该列替换为 int 类型:
1 2 3 4 5 6 7 8
| sample.score.isnull().apply(int) Out[97]: 0 0 1 0 2 0 3 0 4 0 5 1
|
噪声处理
噪声值是指数据中有一个或多个数据与其他数值相比差异性比较大,又称异常值,离群值。
对于单变量,我们可以采用盖帽法,分箱法;
对于多变量,我们可以采用就聚类。
盖帽法
盖帽法将连续变量均值上下三倍标准差范围外的记录替换为均值上下三倍标准差值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def cap(df,quantile=[0.01,0.99]): """ 盖帽法处理异常值 :param df: pd.Series 列,连续变量 :param quantile: 指定盖帽法的上下分位数范围 :return: """ Q01 ,Q99 = df.quantile(quantile).values.tolist() if Q01 > df.min(): x = df.copy() x.loc[x<Q01] = Q01 if Q99 < df.max(): x = df.copy() x.loc[x > Q99] = Q99 return(x)
|
生成一组服从正态分布的随机数,sample.hsit 为直方图。
1 2 3 4
| import matplotlib.pyplot as plt sample = pd.DataFrame({'normall':np.random.randn(1000)}) sample.hist(bins =50) plt.show()
|
对 sample 数据所有列进行盖帽法转换,,下图可以看出盖帽后极端值频数的变化。
1 2 3
| new =sample.apply(cap,quantile=[0.001,0.99]) new.hist(bins=50) plt.show()
|
分箱法
分箱法通过考察数据的”近邻”来光滑有序数据的值。有序值分布到一些桶或箱中。
深分箱,即每个分箱中的样本量一致;
等宽分箱,即每个分箱中的取值范围一致。直方图就是首先对数据进行了等宽分箱,再计算频数画图。
分箱法可以将异常数据包含再箱子中,在进行建模的时候,不直接进行到模型中,因而可以达到处理异常值的目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| # 生成10个标准正态分布的随机数 sample = pd.DataFrame({"normal":np.random.randn(10)}) sample Out[118]: normal 0 -0.028929 1 0.327508 2 -0.596384 3 -2.036334 4 1.452605 5 -0.403936 6 0.315138 7 0.252127 8 -0.775113 9 0.171641
|
等宽分箱
现将sample 按照宽度分位5份,下限中,cut 函数自动选择小于列最小值的一个数值未下限,最大值为上限,等分为5份。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| pd.cut(sample.normal,5) Out[119]: 0 (-0.641, 0.057] 1 (0.057, 0.755] 2 (-0.641, 0.057] 3 (-2.04, -1.339] 4 (0.755, 1.453] 5 (-0.641, 0.057] 6 (0.057, 0.755] 7 (0.057, 0.755] 8 (-1.339, -0.641] 9 (0.057, 0.755] Name: normal, dtype: category Categories (5, interval[float64]): [(-2.04, -1.339] < (-1.339, -0.641] < (-0.641, 0.057] < (0.057, 0.755] < (0.755, 1.453]]
|
使用labels参数指定分箱后的各个水平的标签,
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| pd.cut(sample.normal,bins=5,labels=[1,2,3,4,5]) Out[120]: 0 3 1 4 2 3 3 1 4 5 5 3 6 4 7 4 8 2 9 4 Name: normal, dtype: category Categories (5, int64): [1 < 2 < 3 < 4 < 5]
|
等深分箱
等深分箱中,各个箱的宽度可能不一,但频数是几乎相等,所以可以采用数据的分位数来分箱。现对sample数据进行等深度分二箱,首先要找到2箱的分位数:
1 2 3 4 5 6
| sample.normal.quantile([0,0.5,1]) Out[121]: 0.0 -2.036334 0.5 0.071356 1.0 1.452605 Name: normal, dtype: float64
|
在bins参数中设定分位数区间,为将下边界包含,include_lowest= True,完成等深分箱:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| pd.cut(sample.normal,bins=sample.normal.quantile([0,0.5,1]),include_lowest=True) Out[124]: 0 (-2.037, 0.0714] 1 (0.0714, 1.453] 2 (-2.037, 0.0714] 3 (-2.037, 0.0714] 4 (0.0714, 1.453] 5 (-2.037, 0.0714] 6 (0.0714, 1.453] 7 (0.0714, 1.453] 8 (-2.037, 0.0714] 9 (0.0714, 1.453] Name: normal, dtype: category Categories (2, interval[float64]): [(-2.037, 0.0714] < (0.0714, 1.453]]
|
可以对分组进行标签化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| pd.cut(sample.normal,bins=sample.normal.quantile([0,0.5,1]),include_lowest=True,labels=['bad','good']) Out[125]: 0 bad 1 good 2 bad 3 bad 4 good 5 bad 6 good 7 good 8 bad 9 good Name: normal, dtype: category Categories (2, object): [bad < good]
|
多变量异常值处理-聚类法
通过快速聚类法将数据对象分组成为多个簇,在同一个簇中的对象具有较高的相似度,而不同簇之间的对象差别较大。聚类分析可以挖掘孤立点以发现噪声数据,因为噪声本身就是孤立点。
你的支持是我写作的莫大鼓励