关于机器学习:万字详解AI开发中的数据预处理清洗

4次阅读

共计 9006 个字符,预计需要花费 23 分钟才能阅读完成。

编者按:在现实生活中,大多数数据都须要进行荡涤和预处理,以便在应用数据时达到最佳成果。机器学习流程只能解决数字,因而须要找到一种办法将非数字特色转化为数字示意。本文还介绍了三种缺失值类型:齐全缺失、随机缺失和非随机缺失,并传授如何应用 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.https://lightgbm.readthedocs.io/en/latest/Advanced-Topics.html

2.https://stackoverflow.com/questions/37617390/xgboost-handling-of-missing-values-for-split-candidate-search

3.https://scikit-learn.org/stable/modules/generated/sklearn.imp…

4.https://scikit-learn.org/stable/modules/generated/sklearn.imp…

5.https://github.com/Fuad28/Data-Cleaning-Article/blob/main/Analysis%20with%20Missing%20Data.pdf

6.https://datascience.stackexchange.com/questions/10839/what-is…

7.https://scikit-learn.org/stable/

8.https://contrib.scikit-learn.org/category_encoders

9.http://openrefine.org/

10.https://www.trifacta.com/products/wrangler/

本文经原作者受权,由 Baihai IDP 编译。如需转载译文,请分割获取受权。

原文链接

https://neptune.ai/blog/data-cleaning-process

正文完
 0