前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >初学者使用Pandas的特征工程

初学者使用Pandas的特征工程

作者头像
磐创AI
发布2021-04-21 10:29:14
4.7K0
发布2021-04-21 10:29:14
举报

磐创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_weightOutlet_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具有多种函数,可以使你的工作更加舒适。

我强烈建议你选择任何数据集,并自行尝试所有列出的技术,并在下面评论多少以及哪种方法对你的帮助最大。继续进行讨论将很有趣。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-04-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 磐创AI 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 磐创AI分享
    • 了解数据
      • 用于标签编码的replace()
        • 用于独热编码的get_dummies()
          • 用于分箱的cut() 和qcut()
            • 用于文本提取的apply()
              • 用于频率编码的value_counts() 和apply()
                • 用于聚合功能的 groupby() 和transform()
                  • 用于基于日期和时间特征的Series.dt()
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档