个人Python数据科学工具箱

197 阅读7分钟

个人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))

太棒了,你的包现在应该可以工作了。你现在已经准备好了,不用再像以前那样频繁地重复自己的工作,并对你的分析工作流程进行超级充电。