磐创AI分享
作者 | PROCRASTINATOR
编译 | Flin
来源 | analyticsvidhya
概述
- 特征工程是数据科学生命周期中最关键的步骤之一。
- 我们将讨论pandas如何仅凭一个线性函数使执行特征工程变得更加容易。
介绍
Pandas是用于Python编程语言的开源高级数据分析和处理库。使用pandas,可以轻松加载,准备,操作和分析数据。它是用于数据分析操作的最优选和广泛使用的库之一。
pandas具有简单的语法和快速的操作。它可以轻松处理多达1万条数据。使用pandas Dataframe,可以轻松添加/删除列,切片,建立索引以及处理空值。
现在,我们已经了解了pandas的基本功能,我们将专注于专门用于特征工程的pandas。
![](http://qiniu.aihubs.net/47522Feature Engineering with Pandas.png)
顾名思义,特征工程是一种根据现有数据创建新特征的技术,可以帮助你深入了解数据。建议全面执行EDA的主要原因之一是,我们可以对数据和创建新特征的范围有适当的了解。
特征工程主要有两个原因:
- 根据机器学习算法的要求准备和处理可用数据。大多数机器学习算法与分类数据不兼容。因此,我们需要将该列转换为数字,以便所有有效信息都可以输入到算法中。
- 改善机器学习模型的性能。每个预测模型的最终目标都是获得最佳性能。改善性能的一些方法是使用正确的算法并正确调整参数。但是就我个人而言,我认为创建新特性对改善性能有最大的帮助,因为我们试图为算法提供新信号,而这是之前所没有的。
注意:在本文中,我们将仅了解每种工程方法和功能背后的基本原理。提到的功能范围不仅限于执行这些任务,还可以用于其他数据分析和预处理技术。
目录
- 了解数据
- 用于标签编码的replace()
- 用于热编码的get_dummies()
- 用于分箱的cut() 和qcut()
- 用于文本提取的apply()
- 用于频率编码的value_counts() 和apply()
- 用于聚合功能的 groupby() 和transform()
- 用于基于日期和时间特征的Series.dt()
了解数据
为了更好地理解该概念,我们将处理Big Mart销售预测数据。
问题是:在给定某些变量的情况下,要预测在不同城市的不同商店中存在的产品的销售情况。问题中包含的数据大多与商店和产品有关。
Big Mart销售预测:https://datahack.analyticsvidhya.com/contest/practice-problem-big-mart-sales-iii
让我们导入数据和库,并检查前几行以更好地理解它。
https://gist.github.com/Kamaldeep0077/05a6de2cf5fcf61208b666410fa37bcf
数据具有8,523行和12列。目标变量是Item_Outlet_Sales。
注意:变量中有一些缺失值,例如Item_weight和Outlet_Size。估算这些缺失的值超出了我们的讨论范围,我们将只关注使用pandas函数来设计一些新特性。
用于标签编码的replace()
pandas中的replace函数动态地将当前值替换为给定值。新值可以作为列表,字典,series,str,float和int传递。
注意:应该始终对有序数据执行标签编码,以保持算法的模式在建模阶段学习。
使用replace() 进行标签编码的优点是我们可以手动指定类别中每个组的排名/顺序。
在这里,我们将对具有三个唯一组的Outlet_Loaction_Tier进行标签编码。
代码语言:javascript复制data['Outlet_Location_Type_Encoded'] = data['Outlet_Location_Type']
.replace({'Tier 1': 1, 'Tier 2': 2, 'Tier 3': 3})
data[['Outlet_Location_Type', 'Outlet_Location_Type_Encoded']].head()
在这里,我们以正确的顺序成功地将该列转换为标签编码的列。
用于独热编码的get_dummies()
获取虚拟变量是pandas中的一项功能,可帮助将分类变量转换为独热变量。
独热编码方法是将类别自变量转换为多个二进制列,其中1表示属于该类别的观察结果。
独热编码被明确地用于没有自然顺序的类别变量。示例:Item_Type。如果对此类类别变量执行标签编码,我们就给出了奶制品高于软饮料的模型信号。
代码语言:javascript复制Outlet_Type_Dumm = pd.get_dummies(data=data['Outlet_Type'], columns=['Outlet_Type'], drop_first=True)
pd.concat([data['Outlet_Type'], Outlet_Type_Dumm], axis=1).head()
注意:在代码中,我使用了参数drop_first,它删除了第一个二进制列(在我们的示例中为Grocery Store),以避免完全多重共线性。
在此,每个新的二进制列的值1表示该子类别在原始Outlet_Type列中的存在。
用于分箱的cut() 和qcut()
分箱是一种将连续变量的值组合到n个箱中的技术。合并也可以称为离散化技术,因为我们将连续变量划分为离散变量。
对于某些机器学习算法,有时使用离散变量而不是连续变量会更好。例如:如果将年龄等连续变量转换成年龄段,则可以更好地使用它,并且可以更好地解释该变量。合并连续变量也有助于消除异常值的影响。
pandas具有两个对变量进行分箱的功能,即cut() 和qcut() 。
qcut() : qcut是基于分位数的离散化函数,它试图将bins分成相同的频率组。如果尝试将连续变量划分为五个箱,则每个箱中的观测数量将大致相等。
让我们尝试使用qcut函数对大型超市的Item_MRP变量进行装箱:
代码语言:javascript复制#name of groups
groups = ['Low', 'Med', 'High', 'Exp']
data['Item_MRP_Bin_qcut'] = pd.qcut(data['Item_MRP'], q=4, labels=groups)
data[['Item_MRP', 'Item_MRP_Bin_qcut']].head()
当我们检查这个新变量的频率时:
代码语言:javascript复制# Count of each category
pd.DataFrame(data['Item_MRP_Bin_qcut'].value_counts())
正如预期的那样,该列的每个子类别的观察分布大致相等。
cut() : cut函数还用于离散化连续变量。使用qcut函数,我们的目的是使每个bin中的观察数保持相等,并且我们没有指定要进行拆分的位置,最好仅指定所需的bin数。
在case cut函数中,我们显式提供bin边缘。不能保证每个bin中观测值的分布都是相等的。
如果我们要对像年龄这样的连续变量进行分类,那么根据频率对它进行分类将不是一个合适的方法。
相反,我们想具体地划分儿童年龄,例如从0-14岁到青少年,从15-24岁到60岁以上。在这种情况下,使用cut函数比使用qcut函数更有意义。
让我们尝试使用cut函数对大型超市的Item_MRP变量进行装箱:
代码语言:javascript复制#define bins
bins = [0, 70, 140, 210, 280]
#name of groups
groups = ['Low', 'Med', 'High', 'Exp']
data['Item_MRP_Bin_cut'] = pd.cut(data['Item_MRP'], bins=bins, labels=groups)
data[['Item_MRP', 'Item_MRP_Bin_cut']].head()
当我们检查这个新变量的频率时:
代码语言:javascript复制# Count of each category
pd.DataFrame(data['Item_MRP_Bin_cut'].value_counts())
在这里,我们明确提供了这些箱,并且我们可以清楚地看到每个箱中都有不同数量的观察值。
用于文本提取的apply()
pandas的apply() 函数允许在pandas系列上传递函数并将其传递到变量的每个点。
它接受一个函数作为参数,然后将其应用于数据框的行或列。
我们可以将任何函数传递给apply函数的参数,但是我主要使用lambda函数, 这有助于我在单个语句中编写循环和条件。
使用apply和lambda函数,我们可以从列中存在的唯一文本中提取重复凭证。
例如,我们可以从给定的个人名称中提取标题,或者从Html链接中提取网站名称。这些类型的信号有助于在模型构建阶段改善模型性能。
在我们的大卖场销售数据中,我们有一个Item_Identifier列,它是每个产品的唯一产品ID。此变量的前两个字母具有三种不同的类型,即DR,FD和NC,分别代表饮料,食品和非消耗品。我们可以提取这些字母并将它们用作Item_Code的新变量。
代码语言:javascript复制data['Item_Code'] = data['Item_Identifier'].apply(lambda x: x[0:2])
data[['Item_Identifier', 'Item_Code']].head()
我们已经成功地使用了lambda函数apply创建了一个新的分类变量。
用于频率编码的value_counts() 和apply()
如果名义分类变量中包含许多类别,则不建议使用独热编码。我们不喜欢独热编码的主要原因有两个。
首先,它不必要地增加了尺寸,并且随着尺寸的增加,计算时间也会增加。另一个原因是独热编码二进制变量的稀疏性增加。变量的最大值为0,这会影响模型的性能。
这就是为什么如果我们有一个带有很多类别的名义类别变量,那么我们更喜欢使用频率编码。
频率编码是一种编码技术,用于将分类特征值编码到相应频率的编码技术。这将保留有关分布值的信息。我们将频率归一化,从而得到唯一值的和为1。
在这里,在Big Mart Sales数据中,我们将对Item_Type变量使用频率编码,该变量具有16个唯一的类别。
代码语言:javascript复制# Frequency encoding using value_counts function
Item_Type_freq = data['Item_Type'].value_counts(normalize=True)
# Mapping the encoded values with original data
data['Item_Type_freq'] = data['Item_Type'].apply(lambda x : Item_Type_freq[x])
print('The sum of Item_Type_freq variable:', sum(Item_Type_freq))
data[['Item_Type', 'Item_Type_freq']].head(6)
用于聚合功能的 groupby() 和transform()
Groupby是我的首选功能,可以在数据分析,转换和预处理过程中执行不同的任务。Groupby是一个函数,可以将数据拆分为各种形式,以获取表面上不可用的信息。
GroupBy允许我们根据不同的功能对数据进行分组,从而获得有关你数据的更准确的信息。
关于groupby函数的最有用的事情是,我们可以将其与其他函数(例如Apply,Agg,Transform和Filter)结合使用,以执行从数据分析到特征工程的任务。
为了达到我们的目的,我们将使用具有转换功能的groupby来创建新的聚合功能。
在这里,我们将对变量Item_Identifier和Item_Type进行分组,以查看Item_Outlet_Sales均值。
注意:我们可以对任何类别变量执行groupby函数,并执行任何聚合函数,例如mean, median, mode, count等。
代码语言:javascript复制data['Item_Outlet_Sales_Mean'] = data.groupby(['Item_Identifier', 'Item_Type'])['Item_Outlet_Sales']
.transform(lambda x: x.mean())
data[['Item_Identifier','Item_Type','Item_Outlet_Sales','Item_Outlet_Sales_Mean']].tail()
从第一行,我们可以理解,如果Item_Identifier为FD22,Item_Type为Snack Foods,则平均销售额将为3232.54。
这就是我们如何创建多个列的方式。在执行这种类型的特征工程时要小心,因为在使用目标变量创建新特征时,模型可能会出现偏差。
用于基于日期和时间特征的Series.dt()
日期和时间特征是数据科学家的金矿。
我们仅通过一个日期-时间变量就能检索到的信息量起初是令人惊讶的,但一旦掌握了它,下次我们在数据集中看到一个日期-时间变量时,你就会立即着手处理它。
12-07-2020 01:00:45,看看这个日期,想想这个特定日期的所有可能组成部分。乍一看,我们可以知道我们有一天,月份,年份,小时,分钟和秒。
但是,如果你强调日期,则会发现你还可以计算一周中的某天,一年中的某个季度,一年中的某周,一年中的某天等等。我们可以通过这一日期时间变量创建的新变量的数量没有限制。
但是,并非每个变量都对模型有用,使用所有变量都意味着增加尺寸,甚至向模型馈入噪声。因此,仅提取与数据问题相关的那些变量至关重要。
现在我们有了可以提取哪些变量的想法,剩下唯一的事情就是提取这些特征。为了简化此过程,pandas提供了dt函数,我们可以使用该函数提取上面命名的所有特征以及更多特征。我强烈建议阅读pd.Series.dt文档,以了解每个功能的作用。
注意:到目前为止,我们正在处理的数据集没有任何日期时间变量。在这里,我们使用 NYC Taxi Trip Duration 数据来演示如何通过日期时间变量提取特征。
NYC Taxi Trip Duration:https://www.kaggle.com/c/nyc-taxi-trip-duration/data
在这里,浏览一下数据集:
我们将使用pickup_datetime通过pandas提取特征。
代码语言:javascript复制data['pickup_year'] = data['pickup_datetime'].dt.year
data['pickup_dayofyear'] = data['pickup_datetime'].dt.day
data['pickup_monthofyear'] = data['pickup_datetime'].dt.month
data['pickup_hourofday'] = data['pickup_datetime'].dt.hour
data['pickup_dayofweek'] = data['pickup_datetime'].dt.dayofweek
data['pickup_weekofyear'] = data['pickup_datetime'].dt.weekofyear
仅通过单个日期时间变量,我们就可以创建六个新变量,这些变量在模型构建时肯定会非常有用,这并不奇怪。
注意:我们可以使用pandas dt函数创建新功能的方式有50多种。它取决于问题陈述和日期时间变量(每天,每周或每月的数据)的频率来决定要创建的新变量。
尾注
那就是pandas的力量;仅用几行代码,我们就创建了不同类型的新变量,可以将模型的性能提升到另一个层次。
没有传统的方式或类型可以创建新特征,但是pandas具有多种函数,可以使你的工作更加舒适。
我强烈建议你选择任何数据集,并自行尝试所有列出的技术,并在下面评论多少以及哪种方法对你的帮助最大。继续进行讨论将很有趣。