个人Python数据科学工具箱--第一部分
作为一名数据科学家,你将花很大一部分时间在项目中做重复的工作。你得到一个新的数据集,然后你运行同样的模板代码进行分析。导入数据,检查缺失值,分布检查,清洗,哒哒哒......
我知道,数据集是非常不同的,但我仍然看到,很多时候,同样的步骤在笔记本中被盲目地重复了一遍又一遍。尽管普通的软件工程原则告诉我们不要重复自己,但我们仍然这样做。我开始在自己的工作中注意到这种模式,并感到很沮丧。有没有办法打破这种重复的循环?
我的建议是:建立你的个人图书馆,包括经常需要的分析辅助功能,使你的生活更轻松。把自己看作是数据科学的实践者,随着时间的推移掌握你的工具。与其让它们在你的工作台上到处乱窜,你需要一个中心位置来存储它们。这就是你的个人工具箱。它对每个人都是不同的,但你会认识到它的重要性,并且越是使用它,你就越欣赏它。定期升级和研磨你的刀具。这是你的工具箱。
在这篇文章中,我将向你展示一些围绕Python打包的良好实践,重点是数据科学应用。详细来说,我们要做的是
- 创建一个经常使用的函数包。
- 用单元测试来测试我们的代码。
- 并最终通过git发布。
第一步:创建你的个人工具库
为了开始工作,想想你在开始一个新的数据项目时经常做的步骤(例如在学校、工作或个人)。
以下是我脑海中能想到的经常性任务的清单:
- 分析
- 为所有列/特征绘制分布图
- 对各种数据类型(分类、数字、时间戳等)进行离群检测
- 缺失值的检测和处理
- 数据库和文件IO
-
编写辅助函数,以便更容易地访问特定于你工作的数据存储。它可能是你在你的BigCorp™️使用的丑陋的ERP,或者只是普通的数据库连接器。想出有用的抽象来读/写这些。
-
将文件写入S3和其他文件存储。
-
- 机器学习
- 特征创建
- 超越sklearn的训练-测试分割
- 模型验证
关于Python包的结构化,已经写了很多帖子,我可以热情地推荐以下内容,以便对这个话题进行更深入的讨论。
显然,你的数据科学工具包应该是为你自己的工作和需求量身定做的。所以,自私一点,用你自己的名字命名吧......或者想出一个听起来很酷的名字,斯瓦希里语的字符名怎么样?
对于这篇文章中的例子项目,我们将从一个简单的包开始,名为frnz-sample ,以你的名字命名。
在这里可以找到Github资源库的链接,看看具体的结构。
该项目看起来是这样的:
frnz-sample
├── LICENSE
├── README.md
├── frnz
│ ├── __init__.py
│ ├── analytics.py
│ └── data.py
├── setup.py
└── tests
└── test_analytics.py
frnz目录包含两个核心模块,第一个是analytics.py:
import pandas as pd
from typing import Dict
def count_missing(dataframe: pd.DataFrame) -> Dict[str, int]:
return dict(dataframe.isna().sum())
count_missing 函数将返回所提供的DataFrame中每一列的缺失值的数量。这只是一个便利函数的例子,它将成为你工具包的一部分。随着时间的推移,可以增加更多的内容。
运送玩具数据 🕹
数据科学工具包的另一个关键方面当然是数据!这一点很重要。这主要有两个原因:
- 使用它作为分析任务或数据管道的起点。
- 最重要的是。用它们来对你的核心函数进行单元测试。稍后会有更多关于这个的内容。
与你的包一起运送小的玩具数据集,可以避免外部API调用下载(潜在的)更大的数据集。你可以在其他软件包中找到类似的数据集加载工具,比如scikit-learn。
牢记你的代码所要涵盖的主要功能,并相应地设计你的玩具数据。错别字、缺失数据和异常值只是你在工作中会遇到的一些情况。
在我们的案例中,我创建了一个包含城市名称的小型Pandas DataFrame,可以用于其他分析功能。尽管我们这里没有很多行,但我们可以潜在地测试一些重要的东西:
-
(模糊)重复
- 在这个数据集中有两个 "开普敦",我们怎样才能找到真正的那个?
-
异常值
- 数字。孟买的人口相当多,但真的有那么多吗?
- 分类:悉尼在澳大利亚,但3位数字的国家代码与大多数使用的2位数字的国家ISO代码有偏差。我们如何通过编程找到这些异常情况?
-
缺失值
import pandas as pd cities = pd.DataFrame( data={ "city": [ "Berlin", "Vienna", "Montreal", "Mumbai", "cape-town", "Cape Town", "Sydney", ], "country": ["DE", "AT", "CA", "IN", pd.NA, "ZA", "AUS"], "population": [3750000, 1900000, 1780000, 184100000, 430000, 440000, pd.NA], } )
你已经完成了你的第一个核心功能?是时候进行测试了!
对工具包进行单元测试
对我们的代码进行单元测试可以确保它的性能符合预期。特别是在使用Jupyter笔记本和使用临时代码时,我们经常会遇到使用未经测试的函数的风险。这对于快速分析来说是没有问题的,但如果这些函数被反复使用,它们应该成为你的库的一部分。这意味着要写测试。
下面是一个为我们的analytics 模块中的count_missing 函数进行单元测试的例子。我将使用pytest 框架,因为它提供了在 Python 中开始测试的最简单方法。
在一个名为tests 的文件夹中,创建以下文件test_analytics.py:
from frnz.data import cities
from frnz.analytics import count_missing
import pytest
def test_counting_nas_return_correct_count():
result = count_missing(cities)
expected = {"city": 0, "country": 1, "population": 1}
assert len(result) == len(expected)
assert result["country"] == expected["country"]
首先,我们必须导入该特定测试需要的所有对象。在我们的例子中,这个测试也将导入我们先前创建的样本DataFrame。
测试文件的结构非常简单:你创建一个新函数,通过比较预期结果和实际结果来测试你的代码的特定行为。在这种情况下,我们将用我们的样本cities数据框架来测试函数调用count_missing 的长度和结果。因为我们已经知道我们的样本数据的每一列包含多少缺失值,我们可以在测试中明确地创建一个预期结果的字典。
通过对预期结果和实际结果调用assert ,我们指定了预期的平等性,从而确保了函数的正常工作。
当我们测试我们的代码时,我们应该只需要在我们包的根部的CLI中调用pytest 命令。这将启动测试运行器并自动找到我们刚写的单元测试。确保在包含测试的Python文件的名称中加入test_ 前缀。这基本上是提示pytest将该文件作为一个单元测试来处理。Pytest会运行你的测试,并输出测试是失败还是通过的信息。
通过Github发布
使用git进行版本控制的好处是,你可以直接从Githubpip install 你的软件包(无需发布到PyPI)。只要使用:
pip install -e git+https://github.com/alfranz/frnz-sample.git@master#egg=frnz
和/或在你的项目中指定它作为requirements.txt 的一部分,比如:
frnz @ git+https://github.com/alfranz/frnz-sample.git@master#egg=frnz
在野外使用该软件包💪
现在你应该可以通过pip install ,简单地安装你的新包,并像这样调用你的函数:
import frnz
df = frnz.data.cities
print(frnz.analytics.count_missing(df))
太棒了,你的包现在应该可以工作了。你现在已经准备好了,不用再像以前那样频繁地重复自己的工作,并对你的分析工作流程进行超级充电。