在数据清洗过程当中,主要处理的是缺失值、异常值和重复值。所谓清洗,是对数据集进行丢弃、填充、替换、去重等操做,实现去除异 常、纠正错误、补足缺失的目的。算法
数据缺失分为两种:一是行记录的缺失,这种状况又称数据记录丢失;二是数据列值的缺失,即因为各类缘由致使的数据记录中某些列的值空缺,不一样的数据存储和环境中对于缺失值的表示结果也不一样,例如,数据库中是Null,Python返回对象是None,Pandas或Numpy中是 NaN。数据库
丢失的数据记录一般没法找回,这里重点讨论数据列类型缺失值的 处理,一般有四种思路:后端
这种方法简单明了,直接删除带有缺失值的行记录(整行删除)或者列字段(整列删除),减小缺失数据记录对整体数据的影响。但丢弃 意味着会消减数据特征,如下任意一种场景都不宜采用该方法:bash
相对丢弃而言,补全是更加经常使用的缺失值处理方式,经过必定的方法将缺失的数据补上,从而造成完整的数据记录对于后续的数据处理、分析和建模相当重要。经常使用的补全方法包括:网络
某些状况下,咱们可能没法得知缺失值的分布规律,而且没法对于缺失值采用上述任何一种方法作处理;或者咱们认为数据缺失也是一种 规律,不该该轻易对缺失值随意处理,那么还有一种缺失值处理思路——真值转换。dom
该思路的根本观点是,咱们认可缺失值的存在,而且把数据缺失也做为数据分布规律的一部分,这将变量的实际值和缺失值都做为输入维度参与后续数据处理和模型计算。可是变量的实际值能够做为变量值参与模型计算,而缺失值一般没法参与运算,所以须要对缺失值进行真值转换。ui
以用户性别字段为例,不少数据库集都没法对会员的性别进行补足,但又舍不得将其丢弃,那么咱们将选择将其中的值,包括男、女、未知从一个变量的多个值分布状态转换为多个变量的真值分布状态。spa
在数据预处理阶段,对于具备缺失值的数据记录不作任何处理,也是一种思路。这种思路主要看后期的数据分析和建模应用,不少模型对于缺失值有容忍度或灵活的处理方法,所以在预处理阶段能够不作处理。常见的可以自动处理缺失值的模型包括:KNN、决策树和随机森林、神经网络和朴素贝叶斯、DBSCAN(基于密度的带有噪声的空间聚类)等。这些模型对于缺失值的处理思路是:code
异常数据是数据分布的常态,处于特定分布区域或范围以外的数据一般会被定义为异常或“噪音”。产生数据“噪音”的缘由不少,例如业务运营操做、数据采集问题、数据同步问题等。对异常数据进行处理前,须要先辨别出到底哪些是真正的数据异常。从数据异常的状态看分为两种:orm
大多数数据挖掘或数据工做中,异常值都会在数据的预处理过程当中被认为是噪音而剔除,以免其对整体数据评估和分析挖掘的影响。但在如下几种状况下,无须对异常值作抛弃处理。
该场景是由业务部门的特定动做致使的数据分布异常,若是抛弃异常值将致使没法正确反馈业务结果。
例如:公司的A商品正常状况下日销量为1000台左右。因为昨日举行优惠促销活动致使总销量达到10000台,因为后端库存备货不足致使今日销量又降低到100台。在这种状况下,10000台和100台都正确反映了业务运营的结果,而非数据异常。
异常检测模型是针对总体样本中的异常数据进行分析和挖掘以便找到其中的异常个案和规律,这种数据应用围绕异常值展开,所以异常值 不能作抛弃处理。
异常检测模型经常使用于客户异常识别、信用卡欺诈、贷款审批识别、药物变异识别、恶劣气象预测、网络入侵检测、流量做弊检测等。在这种状况下,异常数据自己是目标数据,若是被处理掉将损失关键信息。
若是数据算法和模型对异常值不敏感,那么即便不处理异常值也不会对模型自己形成负面影响。例如在决策树中,异常值自己就能够做为一种分裂节点。
除了抛弃和保留,还有一种思路可对异常值进行处理,例如使用其余统计量、预测量进行替换,但不推荐使用这种方法,缘由是这会将其中的关键分布特征消除,从而改变原始数据集的分布规律。
数据集中的重复值包括如下两种状况:
去重是重复值处理的主要方法,主要目的是保留能显示特征的惟一数据记录。但当遇到如下几种状况时,请慎重(不建议)执行数据去重。
以变化维度表为例。例如在商品类别的维度表中,每一个商品对应了同1个类别的值应该是惟一的,例如苹果iPhone7属于我的电子消费品, 这样才能将全部全部商品分配到惟一类别属性值中。但当全部商品类别的值重构或升级时(大多数状况下随着公司的发展都会这么作),原有的商品可能被分配了类别中的不一样值。
此时,咱们在数据中使用Full join作跨重构时间点的类别匹配时,会发现苹果iPhone7会同时匹配到我的电子消费品和手机数码两条记录。对于这种状况,须要根据具体业务需求处理:
相关知识点:变化维度表
变化维度表是数据仓库中的概念。维度表相似于匹配表,用来存储静态的维度、属性等数据,而这些数据通常都不会改变。可是变与不变 是一个相对的概念,随着企业的不断发展,不少时候维度也会发生变化。所以在某个时间内的维度是不变的,而从总体来看维度是变化的。 对于维度的变化,有3种方式进行处理:
- 直接覆盖原有值。这种状况下每一个惟一ID就只对应一个属性值,这样作虽然简单粗暴也容易实现,可是没法保留历史信息。
- 添加新的维度行。此时同一个ID会获得两条匹配记录。
- 增长新的属性列。此时不会新增数据行记录,只是在原有的记录 中新增一列用于标记不一样时期的值。具体到企业内使用哪一种方式,一般是由数据库管理员根据实际状况来决定。
在开展分类数据建模工做时,样本不均衡是影响分类模型效果的关键因素之一,解决分类方法的一种方法是对少数样本类别作简单过采样,经过随机过采样采起简单复制样本的策略来增长少数类样本。通过这种处理方式后,也会在数据记录中产生相同记录的多条数据。此时,咱们不能对其中重复值执行去重操做。
对于以分析应用为主的数据集而言,存在重复记录不会直接影响实际运营,毕竟数据集主要用来作分析;但对于事务型的数据而言,重复 数据可能意味着重大运营规则问题,尤为当这些重复值出如今与企业经营中金钱相关的业务场景中,例如重复的订单、重复的充值、重复的预定项、重复的出库申请等。
这些重复的数据记录一般是因为数据采集、存储、验证和审核机制的不完善等问题致使的,会直接反映到前台生产和运营系统。以重复订单为例,假如前台的提交订单功能不作惟一性约束,那么在一次订单中重复点击提交订单按钮,就会触发屡次重复提交订单的申请记录,若是该操做审批经过后,会联动带动运营后端的商品分拣、出库、送货,若是用户接收重复商品则会致使重大损失;若是用户退货则会增长反向订单,并影响物流、配送和仓储相关的各个运营环节,致使运营资源无故消耗、商品损耗增长、仓储物流成本增长等问题。
所以,这些问题必须在前期数据采集和存储时就经过必定机制解决和避免。若是确实产生了此类问题,那么数据工做者或运营工做者能够基于这些重复值来发现规则漏洞,并配合相关部门最大限度下降给企业带来的运营风险。
对于缺失值的处理,主要配合使用sklearn.preprocessing中的Imputer类、Pandas和Numpy。其中因为Pandas对于数据探索、分析和探查的支持较为良好,所以围绕Pandas的缺失值处理较为经常使用。
import pandas as pd # 导入pandas库
import numpy as np # 导入numpy库
from sklearn.preprocessing import Imputer # 导入sklearn.preprocessing中的Imputer库
复制代码
经过Pandas生成一个6行4列,列名分别为'col1'、'col2'、'col3'、'col4'的数据框。同时,数据框中增长两个缺失 值数据。除了示例中直接经过pd.DataFrame来建立数据框外,还可使用数据框对象的df.from_records、df.from_dict、df.from_items来从元组记录、字典和键值对对象建立数据框,或使用pandas.read_csv、pandas.read_table、pandas.read_clipboard等方法读取文件或剪贴板建立数据框。
# 生成缺失数据
df = pd.DataFrame(np.random.randn(6, 4),
columns=['col1', 'col2', 'col3', 'col4']) # 生成一份数据
df.iloc[1:2, 1] = np.nan # 增长缺失值
df.iloc[4, 3] = np.nan # 增长缺失值
print(df)
复制代码
结果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 NaN -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 NaN
5 0.918172 -0.146227 -1.087238 0.376928
复制代码
经过df.null()方法找到全部数据框中的缺失值(默认缺失值是NaN格式),而后使用any()或all()方法来查找含有至少1个 或所有缺失值的列,其中any()方法用来返回指定轴中的任何元素为True,而all()方法用来返回指定轴的全部元素都为True。
# 查看哪些值缺失
nan_all = df.isnull() # 得到全部数据框中的N值
print(nan_all) # 打印输出
复制代码
结果
col1 col2 col3 col4
0 False False False False
1 False True False False
2 False False False False
3 False False False False
4 False False False True
5 False False False False
复制代码
# 查看哪些列缺失
nan_col1 = df.isnull().any() # 得到含有NA的列
print(nan_col1) # 打印输出
复制代码
结果
col1 False
col2 True
col3 False
col4 True
dtype: bool
复制代码
# 查看哪些列缺失
nan_col2 = df.isnull().all() # 得到所有为NA的列
print(nan_col2) # 打印输出
复制代码
结果
col1 False
col2 False
col3 False
col4 False
dtype: bool
复制代码
经过Pandas默认的dropna()方法丢弃缺失值,返回完好失值的数据记录。该代码段执行后返回以下结果(第2行、第5行数据记录被删除):
# 丢弃缺失值
df2 = df.dropna() # 直接丢弃含有NA的行记录
print(df2) # 打印输出
复制代码
结果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
5 0.918172 -0.146227 -1.087238 0.376928
复制代码
经过Sklearn的数据预处理方法对缺失值进行处理。首先经过Imputer方法建立一个预处理对象,其中strategy为默认缺失值的字符串,默认为NaN;
示例中选择缺失值替换方法是均值(默认),还能够选择使用中位数和众数进行替换,即strategy值设置为median或 most_frequent;后面的参数axis用来设置输入的轴,默认值为0,即便用列作计算逻辑。而后使用预处理对象的fit_transform方法对df(数据框对象)进行处理,该方法是将fit和transform组合起来使用。
# 使用sklearn将缺失值替换为特定值
nan_model = Imputer(missing_values='NaN', strategy='mean',
axis=0) # 创建替换规则:将值为NaN的缺失值以均值作替换
nan_result = nan_model.fit_transform(df) # 应用模型规则
print(nan_result) # 打印输出
复制代码
结果
[[ 1.41136738 -0.36790328 2.61005414 -0.59482946]
[ 0.72341364 0.12179985 -0.66436841 -0.7401174 ]
[-0.36736481 -0.17396797 -0.73227893 0.10299754]
[ 1.81116379 0.65385047 0.60561066 1.79355171]
[ 0.0940324 0.64324712 0.25963105 0.18770606]
[ 0.91817218 -0.14622709 -1.08723833 0.37692791]]
复制代码
代码中的第2行第2列和第5行第4列分别被各自列的均值替换。为了验证咱们手动计算各自列的均值,经过使用df['col2'].mean()和df['col4'].mean()分别得到这两列的均值,即-0.4494679289032068和-0.16611331259664791,跟Sklearn返回的结果一致。
使用Pandas作缺失值处理。Pandas对缺失值的处理方法是df.fillna(),该方法中最主要的两个参数是value和method。前者经过 固定(或手动指定)的值替换缺失值,后者使用Pandas提供的默认方法替换缺失值,如下是method支持的方法:
# 使用pandas将缺失值替换为特定值
nan_result_pd1 = df.fillna(method='backfill') # 用后面的值替换缺失值
# 打印输出
print(nan_result_pd1) # 打印输出
复制代码
结果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 -0.173968 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 0.376928
5 0.918172 -0.146227 -1.087238 0.376928
复制代码
# 使用pandas将缺失值替换为特定值
nan_result_pd2 = df.fillna(method='bfill', limit=1) # 用后面的值替代缺失值,限制每列只能替代一个缺失值
# 打印输出
print(nan_result_pd2) # 打印输出
复制代码
结果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 -0.173968 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 0.376928
5 0.918172 -0.146227 -1.087238 0.376928
复制代码
# 使用pandas将缺失值替换为特定值
nan_result_pd3 = df.fillna(method='pad') # 用前面的值替换缺失值
# 打印输出
print(nan_result_pd3) # 打印输出
复制代码
结果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 -0.367903 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 1.793552
5 0.918172 -0.146227 -1.087238 0.376928
复制代码
# 使用pandas将缺失值替换为特定值
nan_result_pd4 = df.fillna(0) # 用0替换缺失值
# 打印输出
print(nan_result_pd4) # 打印输出
复制代码
结果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 0.000000 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 0.000000
5 0.918172 -0.146227 -1.087238 0.376928
复制代码
# 使用pandas将缺失值替换为特定值
nan_result_pd5 = df.fillna({'col2': 1.1, 'col4': 1.2}) # 用不一样值替换不一样列的缺失值
# 打印输出
print(nan_result_pd5) # 打印输出
复制代码
结果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 1.100000 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 1.200000
5 0.918172 -0.146227 -1.087238 0.376928
复制代码
# 使用pandas将缺失值替换为特定值
nan_result_pd6 = df.fillna(df.mean()['col2':'col4']) # 用平均数代替,选择各自列的均值替换缺失值
# 打印输出
print(nan_result_pd6) # 打印输出
复制代码
结果
col1 col2 col3 col4
0 1.411367 -0.367903 2.610054 -0.594829
1 0.723414 0.121800 -0.664368 -0.740117
2 -0.367365 -0.173968 -0.732279 0.102998
3 1.811164 0.653850 0.605611 1.793552
4 0.094032 0.643247 0.259631 0.187706
5 0.918172 -0.146227 -1.087238 0.376928
复制代码
有关异常值的肯定有不少规则和方法,这里使用Z标准化获得的阈值做为判断标准:当标准化后的得分超过阈值则为异常。完整代码以下:
import pandas as pd # 导入pandas库
复制代码
直接经过DataFrame建立一个7行2列的数据框
# 生成异常数据
df = pd.DataFrame({'col1': [1, 120, 3, 5, 2, 12, 13],
'col2': [12, 17, 31, 53, 22, 32, 43]})
print(df) # 打印输出
复制代码
结果
col1 col2
0 1 12
1 120 17
2 3 31
3 5 53
4 2 22
5 12 32
6 13 43
复制代码
本过程当中,先经过df.copy()复制一个原始数据框的副本用来存储Z-Score标准化后的得分,再经过df.columns得到原始数据框的列名,接着经过循环来判断每一列中的异常值。在判断逻辑中,对每一列的数据使用自定义的方法作Z-Score值标准化得分计算,而后跟阈值2.2作比较,若是大于阈值则为异常。
至于为何阈值是2.2?有关数据标准化的话题后面再讨论。
# 经过Z-Score方法判断异常值
df_zscore = df.copy() # 复制一个用来存储Z-score得分的数据框
cols = df.columns # 得到数据框的列名
for col in cols: # 循环读取每列
df_col = df[col] # 获得每列的值
z_score = (df_col - df_col.mean()) / df_col.std() # 计算每列的Z-score得分
df_zscore[
col] = z_score.abs() > 2.2 # 判断Z-score得分是否大于2.2,若是是则是True,不然为False
print(df_zscore) # 打印输出
复制代码
结果
col1 col2
0 False False
1 True False
2 False False
3 False False
4 False False
5 False False
6 False False
复制代码
# 删除异常值所在的行
df_drop_outlier = df[df_zscore['col1'] == False]
print(df_drop_outlier)
复制代码
结果
col1 col2
0 1 12
2 3 31
3 5 53
4 2 22
5 12 32
6 13 43
复制代码
上述过程当中,主要须要考虑的关键点是:如何判断异常值。对于有固定业务规则的可直接套用业务规则,而对于没有固定业务规则的,可 以采用常见的数学模型进行判断,即基于几率分布的模型(例如正态分布的标准差范围)、基于聚类的方法(例如KMeans)、基于密度的方 法(例如LOF)、基于分类的方法(例如KNN)、基于统计的方法(例 如分位数法)等,此时异常值的定义带有较强的主观判断色彩,具体须要根据实际状况选择。
import pandas as pd # 导入pandas库
复制代码
该数据是一个4行2列数据框
# 生成重复数据
data1 = ['a', 3]
data2 = ['b', 2]
data3 = ['a', 3]
data4 = ['c', 2]
df = pd.DataFrame([data1, data2, data3, data4], columns=['col1', 'col2'])
print(df)
复制代码
结果
col1 col2
0 a 3
1 b 2
2 a 3
3 c 2
复制代码
判断数据记录是否为重复值,返回每条数据记录是否重复的结果,取值为True或False。判断方法为df.duplicated(),该方法中 两个主要的参数是subset和keep:
# 判断重复数据
isDuplicated = df.duplicated() # 判断重复数据记录
print(isDuplicated) # 打印输出
复制代码
结果
0 False
1 False
2 True
3 False
dtype: bool
复制代码
操做的核心方法是 df.drop_duplicates(),该方法的做用是基于指定的规则判断为重复值以后,删除重复值,其参数跟df.duplicated()彻底相同。在该部分方法示例中,依次使用默认规则(所有列相同的数据记录)、col1列相 同、col2列相同以及指定col1和col2彻底相同四种规则进行去重。
# 删除重复值
new_df1 = df.drop_duplicates() # 删除数据记录中全部列值相同的记录
print(new_df1) # 打印输出
复制代码
结果
col1 col2
0 a 3
1 b 2
3 c 2
复制代码
# 删除重复值
new_df2 = df.drop_duplicates(['col1']) # 删除数据记录中col1值相同的记录
print(new_df2) # 打印输出
复制代码
结果
col1 col2
0 a 3
1 b 2
3 c 2
复制代码
# 删除重复值
new_df3 = df.drop_duplicates(['col2']) # 删除数据记录中col2值相同的记录
print(new_df3) # 打印输出
复制代码
结果
col1 col2
0 a 3
1 b 2
复制代码
# 删除重复值
new_df4 = df.drop_duplicates(['col1', 'col2']) # 删除数据记录中指定列(col1/col2)值相同的记录
print(new_df4) # 打印输出
复制代码
结果
col1 col2
0 a 3
1 b 2
3 c 2
复制代码