查看原文
其他

如何优雅地使用pdpipe与Pandas构建管道?

CSDN App AI科技大本营 2020-02-17


作者 | Tirthajyoti Sarkar
译者 | 清儿爸
编辑 | 夕颜
出品 | AI科技大本营(ID: rgznai100) 
【导读】Pandas 是 Python 生态系统中的一个了不起的库,用于数据分析和机器学习。它在 Excel/CSV 文件和 SQL 表所在的数据世界与 Scikit-learn 或 TensorFlow 施展魔力的建模世界之间架起了完美的桥梁。 数据科学流通常是一系列的步骤:数据集必须经过清理、缩放和验证,之后才能被强大的机器学习算法使用。 当然,这些任务可以通过 Pandas 等包提供的许多单步函数或方法来完成,但更为优雅的方式是使用管道。在几乎所有的情况下,通过自动执行重复性任务,管道可以减少出错的机会,并能够节省时间。
在数据科学领域中,具有管道特性的软件包有 R 语言的 dplyr 和 Python 生态系统中的 Scikit-learn。
 
要了解它们在机器学习工作流中的应用,你可以读这篇很棒的文章:
https://www.kdnuggets.com/2017/12/managing-machine-learning-workflows-scikit-learn-pipelines-part-1.html
 
Pandas 还提供了 `.pipe` 方法,可用于类似的用户定义函数。但是,在本文中,我们将讨论的是非常棒的小库,叫 pdpipe,它专门解决了 Pandas DataFrame 的管道问题。
 

使用 Pandas 的流水线

 
Jupyter Notebook 的示例可以在我的 Github 仓库中找到:

https://github.com/tirthajyoti/Machine-Learning-with-Python/blob/master/Pandas%20and%20Numpy/pdpipe-example.ipynb。

让我们看看如果使用这个库来构建有用的管道。
 

数据集

 
为了演示,我将使用美国房价的数据集,可从 Kaggle 下载:

https://www.kaggle.com/vedavyasv/usa-housing

我们可以在 Pandas 中加载数据集,并显示其汇总的统计信息,如下所示:
               
但是,数据集中还有一个“Address”字段,其中包含了文本数据。
                

添加大小限定符列

 
在这个演示中,我们在数据集中添加了一个列来限定房屋的大小,代码如下所示:
               
经过此步骤之后,数据集如下所示:
              

最简单的管道:一次操作

 
我们从最简单的管道开始,它只包含一次操作(不必担心,我们很快就会增加复杂性的)。
 
让我们假设机器学习团队和领域专家说他们认为我们可以安全地忽略用于建模的数据 `Avg. Area House Age` 。因此,我们将从数据集中删除这一列。
 
对于这个任务,我们使用 pdpipe 中的 `ColDrop` 来创建一个管道对象 `drop_age`,并将 DataFrame 传递给这个管道。

import pdpipe as pdpdrop_age = pdp.ColDrop(‘Avg. Area House Age’)df2 = drop_age(df)

 
正如预期的那样,生成的 DataFrame 如下所示:
               

只需添加管道链级

 
只有当我们能够进行多个阶段时,管道才是有用和实用的。在 pdpipe 中有多种方法可以实现这一点。但是,最简单、最直观的方法是使用 + 运算符。这就像手工连接管道一样!
 
比方说,除了删除 `age` 列之外,我们还希望对 `House size` 的列进行独热编码,以便可以轻松地在数据集上运行分类或回归算法。

pipeline = pdp.ColDrop(‘Avg. Area House Age’)
pipeline+= pdp.OneHotEncode(‘House_size’)
df3 = pipeline(df)
因此,我们首先使用 `ColDrop` 方法创建了一个管道对象来删除 `Avg. Area House Age` 列。此后,我们只需使用常用的 Python 的 `+=` 语法将 `OneHotEncode` 方法添加到这个管道对象中即可。
 
生成的 DataFrame 如下所示。请注意,附加的指示列 `House_size_Medium` 和 `House_size_Small` 是由独热编码创建的。
              

根据行值删除某些行

 
接下来,我们可能希望根据行值来删除它们。具体来说,我们可能希望删除房价低于 25 万的所有数据。我们有 `ApplybyCol` 的方法来讲删除用户蒂尼的函数应用到 DataFrame,还有一个方法 `ValDrop` 根据特定值来删除某些行。我们可以轻松地将这些方法链接到管道,以便能够有选择地删除行(我们仍在向现有的管道对象中添加内容,该对象已经完成了列删除和独热编码的其他工作)。
 

def price_tag(x): if x>250000: return 'keep' else: return 'drop'pipeline+=pdp.ApplyByCols('Price',price_tag,'Price_tag',drop=False)pipeline+=pdp.ValDrop(['drop'],'Price_tag')pipeline+= pdp.ColDrop('Price_tag')


第一个方法是通过应用用户定义的函数 `price_tag()`,根据 `Price` 列中的值来对行进行标记。
              
第二种方法是,在  `Price_tag` 中查找字符串 `drop`,并删除那些匹配的行。最后,第三个方法就是删除 `Price_tag` 标签列,清理 DataFrame。毕竟,这个 `Price_tag`列只是临时需要的,用于标记特定的行,在达到目的后就应该将其删除。
 
所有这些都是通过简单地链接同一管道上的各个阶段来完成的!
 
现在,我们可以回顾一下,看看我们的管道从一开始对 DataFrame 都做了什么工作:
 
  • 删除特定的列。
  • 独热编码,用于建模的分类数据列。
  • 根据用户定义函数对数据进行标记。
  • 根据标记删除行。
  • 删除临时标记列。
 
所有这些,使用的是以下五行代码:
 

pipeline = pdp.ColDrop('Avg. Area House Age')pipeline+= pdp.OneHotEncode('House_size')pipeline+=pdp.ApplyByCols('Price',price_tag,'Price_tag',drop=False)pipeline+=pdp.ValDrop(['drop'],'Price_tag')pipeline+= pdp.ColDrop('Price_tag')
df5 = pipeline(df)

最近版本更新:直接删除行!

 
我与包作者 Shay Palachy 进行了精彩的讨论,他告诉我,该包的最新版本可以用 lambda 函数,仅用一行代码即可完成行的删除(满足给定的条件),如下所示:
 

pdp.RowDrop({‘Price’: lambda x: x <= 250000})
 

Scikit-learn 与 NLTK

 
还有许多更有用、更直观的 DataFrame 操作方法可用于 DataFrame 操作。但是,我们只是想说明,即使是 Scikit-learn 和 NLTK 包中的一些操作,也包含在 pdpipe 中,用于创建非常出色的管道。
 

Scikit-learn 的缩放估算器

 
建立机器学习模型最常见的任务之一是数据的缩放。Scikit-learn 提供了集中不同类型的缩放,例如,最小最大缩放,或者基于标准化的缩放(其中,数据集的平均值被减去,然后除以标准差)。
 
我们可以在管道中直接链接这些缩放操作。下面的代码段演示了这种用法:
 

pipeline_scale = pdp.Scale('StandardScaler',exclude_columns=['House_size_Medium','House_size_Small'])df6 = pipeline_scale(df5)

本文中,我们应用了 Scikit-learn 包中的 `StandardScaler` 估算器来转换数据以进行聚类或神经网络拟合。我们可以选择性地排除那些无需缩放的列,就像我们在本文中对指示列 `House_size_Medium` 和 `House_size_Small` 所做的那样。
 
瞧!我们得到了缩放后的 DataFrame:
               

NLTK 的词法分析器

 
我们注意到,DataFrame 中的 Address 字段现在几乎毫无用处。但是,如果我们可以从这些字符串中提取邮政编码或州名,它们可能对某种形式的可视化或机器学习任务有用。
 
为此,我们可以使用 Word Tokenizer(单词标记器)来实现这一目的。NTLK 是一个流行而强大的 Python 库,用于文本挖掘和自然语言处理,并提供了一系列的标记器方法。在本文示例中,我们客户使用一个这样的标记器来拆分 Address 字段中的文本,并从中提取州名。我们注意到,州名就是地址字符串中的倒数第二个单词。因此,下面的链式管道就可以帮我们完成这项工作:
 

def extract_state(token): return str(token[-2])
pipeline_tokenize=pdp.TokenizeWords('Address')pipeline_state = pdp.ApplyByCols('Address',extract_state,result_columns='State')
pipeline_state_extract = pipeline_tokenize + pipeline_state
df7 = pipeline_state_extract(df6

生成的 DataFrame 如下所示:
              

总结

 
如果我们对本文这个演示中显示的所有操作进行总结,则如下所示:
               
所有这些操作都可以在类似类型的数据集上频繁使用,并在数据集准备好进入下一级建模之前,能有一组简单的顺序代码块作为预处理操作来执行,将是非常棒的。
 
流水线是实现统一的顺序代码块集的关键。Pandas 是机器学习和数据科学团队中用于这类数据预处理任务的最广泛使用的 Python 库,而 pdpipe 则提供了一种简单而强大的方法,可以使用 Pandas 类型操作构建管道,可以直接应用于 Pandas DataFrame 对象。
 
你可以自己探索这个库,为你的特定数据科学任务构建更强大的管道。
 
原文链接:
https://towardsdatascience.com/https-medium-com-tirthajyoti-build-pipelines-with-pandas-using-pdpipe-cade6128cd31

(*本文为AI科技大本营翻译文章,转载请微信联系 1092722531)



精彩推荐




2020年,由 CSDN 主办的「Python开发者日」活动(Python Day)正式启动。我们将与 PyCon 官方授权的 PyCon中国社区合作,联手顶尖企业、行业与技术专家,通过精彩的技术干货内容、有趣多元化的活动等诸多体验,共同为中国 IT 技术开发者搭建专业、开放的技术交流与成长的家园。未来,我们和中国万千开发者一起分享技术、践行技术,铸就中国原创技术力量。


【Python Day——北京站】现已正式启动,「新春早鸟票」火热开抢!2020年,我们还将在全国多个城市举办巡回活动,敬请期待!
活动咨询,可扫描下方二维码加入官方交流群~

CSDN「Python Day」咨询群 🔽
来~一起聊聊Python

如果群满100人,无法自动进入,可添加会议小助手微信:婷婷,151 0101 4297(电话同微信)



推荐阅读

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存