本文正在参加 人工智能创作者扶持计划
编者按:在现实生活中,大多数数据都需求进行清洗和预处理,以便在运用数据时到达最佳作用。机器学习流程只能处理数字,因而需求找到一种办法将非数字特征转化为数字表示。本文还介绍了三种缺失值类型:完全缺失、随机缺失和非随机缺失,并教授怎么运用Python来检测和处理缺失值。
经过阅览本文,我信任你将了解什么是数据清洗,还能把握数据清洗的进程以及怎么进行实操。
以下是译文,Enjoy!
作者|Fuad Adio
编译| 岳扬
数据清洗(Data Cleaning)是经过修正、增加或删除数据的方式为数据分析做准备的进程,这个进程通常也被称为数据预处理(Data Preprocessing)。关于数据科学家和机器学习工程师来说,熟练把握数据清洗全流程至关重要,由于数据预处理后的质量将直接影响他们或训练的模型从数据中取得的一切结论和观念(insights) 。
在这篇博文中,咱们将重点叙述类别型特征(categorical feature)方面的数据整理概念(本文第5部分),给出适宜的图片以协助了解,并供给代码演示等。
在本文结束时,我信任你不只会了解什么是数据清洗,还能完美地把握数据清洗的进程,怎么进行实操,以及最重要的是怎么从你的数据中得到最好的结果。
01 为什么咱们需求清洗数据?
有时,在咱们可以从数据中提取有用的信息之前,需求对数据进行清洗/预处理。大多数现实生活中的数据都有许多需求处理的地方,如缺失值、非信息特征等,因而,在运用数据之前,咱们一向需求对其进行清洗,以便在运用数据时到达最佳作用。
以机器学习流程为例,它的作业方针只要数字。假如咱们计划运用具有文本、日期时刻特征和其他非数字特征的数据,咱们需求找到一种办法,用数字****来表示它们,而不丢掉它们所携带的信息。
比方说一个简略的逻辑回归模型仅仅用一个线性函数将因变量映射到自变量上,如:y= wx + b。其间,w是权重,可以是任何数字,b是误差,也是一个数字。
假如给你一组数据;[小、中、大],你会发现不或许核算出:y=w*small+b。
但假如你把“小”编码为1,“中”编码为2,“大”的编码为3,从而把你的数据转化为[1,2,3],你会发现你不只可以核算y=w*1+b,并且其间编码的信息依然被保留。
02 数据清洗有哪些进程?
数据清洗是咱们在为数据分析做准备的进程中对数据进行的一系列操作的统称。
数据清洗的进程包含:
- 处理缺失值(Handling missing values)
- 对类别型特征进行编码(Encoding categorical features)
- 异常值检测(Outliers detection)
- 改换(Transformations)
- …
后续咱们将重点打开处理缺失值和对类别型特征进行编码。
03 处理缺失值(Handling missing values)
在进行数据预处理时遇到的最常见的问题之一便是咱们数据中存在缺失值。这个情况是十分常见的,或许由于 :
- 填写数据的人有意或无意的遗失,或者数据根本不适合填在此处。
- 作业人员将数据输入电脑时呈现遗失。
数据科学家假如不注意,或许会从包含缺失值的数据中得出错误的推论,这便是为什么咱们需求研讨缺失值并学会有用地解决它。
早期的机器学习库(比方scikit learn)不答应将缺失值传入。这就会带来必定的挑战,由于数据科学家在将数据传递给scikit learn ML模型之前,需求迭代许多办法来处理缺失值。最新的机器学习模型和渠道现已解除了这一妨碍,特别是基于梯度提升机(gradient boosting machines)的一些算法或东西,如Xgboost、Catboost、LightGBM等等。
我特别看好的是Catboost办法,它答运用户在三个选项(Forbidden, Min, and Max)中进行挑选。Forbidden将缺失值视为错误,而Min将缺失值设定为小于特定特征(列)中的一切其他值。这样,咱们就可以必定,在对特征进行根本的决策树分裂(decision tree splitting)时,这些缺失值也会被考虑在内。
LightGBM[1]和XGboost[2]也能以适当便利的方式处理缺失值。然而,在进行预处理时,要尽或许多地测验各种办法。运用像咱们上面评论的那些库,其他的东西,如automl等等。
缺失值一般分为三类,即:
1)完全随机缺失(MCAR) 。假如咱们没有任何信息、理由或任何可以协助核算它的东西,那么这个缺失值便是完全随机缺失。例如,”我是一个很困的研讨生,不小心把咖啡打翻在咱们搜集的纸质查询表上,让咱们失去了一切原本咱们会有的数据。”
2)随机缺失(MAR) 。假如咱们有信息、理由或任何东西(特别是来自其他已知值)可以协助核算,那么这个缺失值便是随机缺失。例如,”我进行一项查询,其间有一个关于个人收入的问题。但是女人不太或许直接答复关于收入的问题。”
3)非随机缺失(NMAR) 。缺失的变量的值与它缺失的原因有关。例如,”假如我进行的查询包含一个关于个人收入的问题。那些低收入的人明显不太或许答复这个问题”。因而,咱们知道为什么这种数据点或许缺失。
04 怎么运用Python检测缺失值?
在咱们处理缺失值之前,咱们理应学习怎么检测它们,并依据缺失值的数量、咱们有多少数据等等来决议怎么处理咱们的数据。我喜爱并常常运用的一个办法是为某一列设置一个阈值,以决议它是可以修复还是无法修复。
下面,你会看到一个函数,它完成了咱们在之前评论的一些想法。
def missing_removal(df, thresh, confirm= None):
holder= {}
for col in df.columns:
rate= df[col].isnull().sum() / df.shape[0]
if rate > thresh:
holder[col]= rate
if confirm==True:
df.drop(columns= [i for i in holder], inplace= True)
return df
else:
print(f' Number of columns that have Nan values above the thresh specified{len(holder)}')
return holder
Quick note
假如confirm参数设置为True,一切缺失值百分比高于设定阈值的列都会被删除;假如confirm参数设置为None或False,该函数会回来数据中一切列的缺失值百分比列表。现在去你的数据上试试吧!
4.1 统计归纳法(Statistical imputation)
这是一种被长期证明有用的办法。只需求简略地用某一列的平均数、中位数、模式来填补该列中的缺失数据。这很有用,正在阅览的伙伴们,请信任我!
Scikit-learn供给了一个名为SimpleImputer[3]的子类,便是以这种方式处理咱们的缺失值。
下面是一个简短的代码描绘,可以有助于咱们更好地了解统计归因法。
from sklearn.impute import SimpleImputer
# store the columns of the dataframe 存储dataframe的一切列
cols= df.columns
#instantiate the SimpleImputer subclass 实例化SimpleImputer子类
#Depending on how you want to imput, you can use most_frequent, mean, median and constant 依据你想输入的方式,你可以运用most_frequent、mean、median和constant。
imputer= SimpleImputer(strategy= 'most_frequent')
df= imputer.fit_transform(df)
# convert back to dataframe 转换回dataframe
df= pd.DataFrame(df, columns= cols)
4.2 链式方程多重填补 Multiple Imputation by Chained Equations (MICE)
在这种办法中,每一列和它的缺失值被建模为数据中其他列的函数。 这个进程不断重复,直到之前核算出的值与当时值之间的公役十分小,并且低于给定的阈值。
Scikit-learn供给了一个名为IterativeImputer[4]的子类,可以用它处理缺失值。
下面是一个简短的代码描绘,期望能帮你了解这种办法。
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
# store the columns of the dataframe 存储dataframe的一切列
cols= df.columns
#instantiate IterativeImputer subclass 实例化IterativeImputer子类
imputer= IterativeImputer(max_iter= 3)
df= imputer.fit_transform(df)
# convert back to dataframe 转换回dataframe
df= pd.DataFrame(df, columns= cols)
期望上述这些内容足以让你有用地处理缺失值。
关于缺失值的更多信息,请检查Matt Brems的这份资料[5]。
05 对类别型特征进行编码(Encoding categorical features)
5.1 什么是类别型特征
类别型特征是只取离散值的特征。它们不具有接连值,如3.45,2.67等。一个类别型特征的值可以是大、中、小,1-5的排名,是和不是,1和0,黄色、赤色、蓝色等等。它们根本上代表类别,如年龄组、国家、颜色、性别等。
许多时分类别型特征是以文本格局呈现的,有些时分它们是以数字格局呈现的(大多数人常常无法辨认这种格局的类别型特征)。
5.2 怎么辨认类别型特征?
怎么辨认类别型特征不该该是一个大问题,大多数时分,分类特征是以文本格局呈现的。
假如有一种排名方式,并且它们实际上是以数字格局呈现的,那怎么办?此时要做的便是检查一列中仅有值的数量,并将其与该列中的行数进行比较。 例如,一列有2000行,只要5或10个仅有值,你很或许不需求他人来告诉你该列是分类列。这没有什么规矩,只能依靠直觉,你或许是对的,也或许是错的。
5.3 类别型特征编码办法
- 给定一个类别型特征,正如前文咱们所研讨的那样,咱们面对的问题是将每个特征中的共同类别转换为数字,一起不丢掉其间编码的信息。基于一些可调查的特征,有各种类别型特征的编码办法。一起也有两类类别型特征:
- 有序的类别型特征:在这一特定特征中,类别之间存在固有的顺序或关系,例如巨细(小、大、中)、年龄组等。
- 无序的类别型特征:该特征的类别之间没有合理的顺序,如国家、城市、名称等。
处理上述两类的办法是不同的。我在处理无序的类别型特征时运用下面这些办法:
- 独热编码(One-hot encoding)
- 频数编码(Frequency/count encoding)
- 方针编码/均值编码(Target mean encoding)
- 有序整数编码(Ordered integer encoding)
- 二进制编码(Binary encoding)
- 留一法(Leave-one-out)编码
- 证据权重编码(Weight of evidence encoding)
关于有序的类别型特征,咱们只运用
- 标签编码或序号编码(Label encoding or ordinal encoding)
现在,咱们将测验一个接一个地研讨其间的一些办法。并尽或许地用Python完成它们,主要是运用名为category_encoders的Python库。
可以运用 pip install category_encoders 来安装这个库。
1) 独热编码(One-hot encoding)
独热编码是对无序的类别型特征(nominal categorical features)进行编码的最有用办法之一。这种办法为列中的每个类别创建一个新的二进制列。理想情况下,咱们会删除其间一列以防止各列之间的共线性,因而,具有K个仅有类别的特征会在数据中产生额外的K-1列。
这种办法的缺点是,当一个特征有许多仅有的类别或数据中有许多类别型特征时,它就会扩展特征空间(feature space)。
上图解说了独热编码的概念,以该种方式对特征进行编码可以消除一切方式的分层结构。
下面介绍怎么在Python中完成这种办法。
import pandas as pd
data= pd.get_dummies(data, columns, drop_first= True)
#check https://pandas.pydata.org/docs/reference/api/pandas.get_dummies.html for more info
2)频数编码(Frequency/count encoding)
这种办法同样十分有用。它依据无序的类别型特征在特征(列)中呈现的频率为无序的类别型特征引入了分层结构(hierarchy)。 它与计数编码十分类似,由于计数编码可以取任何值,而频率编码则规一化为0到1之间。
下面介绍频数编码在Python中的完成:
# Frequency encoding 频率编码
# cols is the columns we wish to encode cols参数是咱们要编码的那些列
#df is the dataFrame df参数是dataFrame
def freq_enc(df, cols):
for col in cols:
df[col]= df[col].map(round(df[col].value_counts()/len(df),4))
return df
# count encoding 计数编码
def count_enc(df, cols):
for col in cols:
df[col]= df[col].map(round(df[col].value_counts()))
return df
3) 方针编码/均值编码(Target mean encoding)
这种办法的思路是十分好的!它有一个十分共同的地方,便是它在核算进程中运用了方针列,这在一般的机器学习运用进程中是十分罕见的。类别型特征中的每一个类别都被替换成该类别方针列的平均值。
该办法十分好,但是假如它编码了太多关于方针列的信息,或许会导致过拟合。因而,在运用该办法之前,咱们需求确保这个类别型特征与方针列没有高度关联。
测试数据经过映射运用来自训练数据的存储值进行编码。
下面介绍方针编码/均值编码在Python中的完成:
# target mean encoding
#target_col is the name of the target column (str)
def target_mean_enc(df, cols, target_col):
mean_holder= {}
for col in cols:
col_mean= {}
cat= list(df[col].unique())
for i in cat:
data= df[df[col]== i]
mean= np.mean(data[target_col])
col_mean[i]= mean
mean_holder[col]= col_mean
return mean_holder
上面的函数回来一个字典,其间包含被编码列的平均值,然后将字典映射到数据上。见下图:
4) 有序整数编码(Ordered integer encoding)
这种办法与方针编码/均值编码十分类似,仅仅它更进一步,它依据方针均值(target mean)的巨细对类别进行排序。
在完成有序整数编码后,dataframe看起来像这样:
下面介绍有序整数编码在Python中的完成:
def ordered_interger_encoder(data, cols, target_col):
mean_holder= {}
for col in cols:
labels = list(enumerate(data.groupby([col])[target_col].mean().sort_values().index))
col_mean= {value:order for order,value in labels}
mean_holder[col]= col_mean
return mean_holder
5) 二进制编码(Binary encoding)
二进制编码的作业原理是绝无仅有的,几乎与独热编码类似,不过还是有许多立异点。首先,它依据那些仅有特征(unique features)在数据中的呈现方式为其分配level(不过这个level没有任何意义) 。然后,这些level被转换为二进制。最终各个数字被划分到不同的列。
下面介绍了运用category_encoders库进行二进制编码的演示:
from category_encoders import BinaryEncoder
binary= BinaryEncoder(cols= ['STATUS'])
binary.fit(data)
train= binary.transform(train_data)
test= binary.transform(test_data)
6) 留一法(Leave-one-out)编码
这种办法也十分类似于方针编码/均值编码,仅仅在每个级别上都核算方针均值,而不是只考虑在特定级别上。不过,方针编码/均值编码仍用于测试数据(检查更多信息[6])。
下面介绍留一法(Leave-one-out)编码在Python中的完成:
from category_encoders import leave_one_out
binary= leave_one_out(cols= ['STATUS'])
binary.fit(data)
train= binary.transform(train_data)
test= binary.transform(test_data)
7) 证据权重编码(Weight of evidence encoding)
这是一种现已在信用风险分析中运用了长达七十年的办法。它通常用于逻辑回归使命的特征转化,由于它有助于提醒咱们之前或许看不到的特征之间的相关性。这种办法只能用于分类使命。
它经过对列中的每个类别运用ln(p(good)/p(bad))来转换分类列。
p(good)是方针列的一个类别,例如p(1),而p(bad)是第二种类别,或许仅仅p(0)。
下面介绍了运用category_encoders库进行证据权重编码的演示:
from category_encoders import WOEEncoder
binary= WOEEncoder(cols= ['STATUS'])
binary.fit(data)
train= binary.transform(train_data)
test= binary.transform(test_data)
8) 标签编码(Label Encoding)和序号编码(Ordinal Encoding)
这种办法用于对无序的类别型特征进行编码,咱们只需求依据咱们可以推断出的巨细为每个类别分配数字。
下面介绍这种办法在Python中的完成:
df['size']= df['size'].map({'small':1, 'medium':2, 'big':3})
df
06 数据清洗东西和库
在该文章中提到了一些机器学习库,如scikit learn[7]和category_encoders[8]。还有其他一些有助于数据预处理的Python库,包含:Numpy, Pandas, Seaborn, Matplotlib, Imblearn等等。
然而,假如你是那种不喜爱写太多代码的人,你可以看看OpenRefine[9]、Trifacta Wrangler[10]等这些东西。
07 总结
到此为止,咱们所评论的大部分概念的代码完成与实例都可以在本文找到。我期望这篇文章可以让你对特征编码(Categorical Encoding) 的概念和怎么填补缺失值有一个较深刻的认识。
假如你要问应该运用哪种办法?
数据清洗是一个反复的进程,因而,你可以随意测验,并坚持运用对你的数据最有用的那一种。
END
参考资料
1.lightgbm.readthedocs.io/en/latest/A…
2.stackoverflow.com/questions/3…
3.scikit-learn.org/stable/modu…
4.scikit-learn.org/stable/modu…
5.github.com/Fuad28/Data…
6.datascience.stackexchange.com/questions/1…
7.scikit-learn.org/stable/
8.contrib.scikit-learn.org/category_en…
9.openrefine.org/
10.www.trifacta.com/products/wr…
本文经原作者授权,由Baihai IDP编译。如需转载译文,请联系获取授权。
原文链接:
neptune.ai/blog/data-c…