数据科学测试 2:测试的基本原则

所有软件测试的基本原则是:准备、执行、断言

  1. 准备:为测试做准备,例如加载一些数据
  2. 执行:执行你想要测试的操作,例如将数据传递给一个函数
  3. 断言:检查函数的输出是否符合你的期望
  4. 你可以测试什么:
  1. 函数是否返回了某样东西?
  2. 它是否返回了正确类型的对象?
  3. 返回的对象是否具有正确的特性,例如正确的维度数量?
  4. 返回的对象是否合理,例如温度值是否在合理的范围内?
  5. 等等……

使用自动化测试框

在实践中,你需要一个自动化测试框架来:

  1. 设置一个Python解释器
  2. 在你的代码目录中查找测试
  3. 运行所有测试并报告结果

我非常推荐第三方库 pytest 而不是内置的单元测试模块:

  1. 使用 pytest 命名测试的语法很直观
  2. pytest 提供了许多实用的第三方扩展,例如计算测试覆盖率或并行运行测试
  3. pytest 具有更高级的功能,例如通过参数化测试遍历一系列数据组合,或使用 fixtures 为多个测试设置相同的数据

到目前为止,我只在某些功能(例如测试某个测试是否会返回异常)上使用了内置的单元测试模块。

简单测试示例

让我们看一个简单的示例。在这个示例中,我们:

  1. 读取一个CSV文件
  2. 将所有列名重命名为小写
  3. 将“survived”列从整数类型转换为分类类型
  4. 创建一个新的“family_size”列,它是兄弟姐妹数(sibsp)和父母/子女数(parch)的总和:
def loadAndCleanCSV():
  df = pd.read_csv('data/titanic.csv')
  df = df.rename(columns={col:col.lower() for col in df.columns})
  df.loc[:, "survived"] = df["survived"].astype(pd.CategoricalDtype())
  df['family_size'] = df.loc[:,['sibsp','parch']].sum(axis=1)
  return df

在pytest框架中,我们通过添加一个新函数来进行测试,该函数以test_开头,或者在这个例子中为test_loadAndCleanCSV,这样我们就知道它针对的是哪个函数。

我们的测试原则是Arrange(准备)、Act(执行)、Assert(断言)。在这个简单示例中,Arrange和Act阶段很简单,因为我们不需要向函数传递任何参数:

def test_loadAndCleanCSV()
    outputDf = loadAndCleanCSV()

现在是Assert阶段,问题是:我们要测试什么?

以下是我对数据科学代码进行的一些常见测试:

  1. 在几乎每个测试函数中,我都会测试函数输出的类型。这看起来可能太明显了,但有时你会发现,例如,你不经意间将DataFrame缩减为了Series。
  2. 我通常还会测试DataFrame的一些元数据——它是否有预期的行数和/或列数?
  3. 测试DataFrame的dtypes也是一个好主意——在这个例子中,我们将限制为检查“survived”列从整数到分类的转换是否成功。
def test_loadAndCleanCSV()
    outputDf = loadAndCleanCSV()
    assert isinstance(outputDf,pd.DataFrame)
    assert df.shape == (1112,13)
    assert pd.api.types.is_categorical_dtype(df["survived"])

对于许多数据科学对象的测试,如DataFrame,仅使用标准的Python断言语句就足够了。这个语句测试其后的条件是否为True。如果条件不满足,则会引发一个AssertionError。

许多数据科学库都带有方便的功能来测试它们生成的对象。在上面的函数最后一行中,我们使用了Pandas的内置函数:pd.api.types.is_categorical_dtype。在pd.api.types命名空间中还有许多这样的方便函数(这些函数在处理复杂的数据类型,如日期时间时特别有用)。

一旦我在src目录中的某个地方将测试写入自己的脚本中,我就可以使用pytest来运行它们。我通常使用python -m标志将其作为模块来运行:

python -m pytest src

然后,pytest会设置一个全新的Python解释器,找到所有以test_开头的测试函数并运行它们。

测试数据集

  1. 始终使用尽可能小的测试数据集
  2. 在项目一开始就创建测试数据集
  3. 轻松地在不同的测试数据集和完整数据集之间切换
  4. 拥有多个大小不同的测试数据集
  5. 可以显示当数据集变大时是否会出现新的问题
  6. 可以估算运行完整数据集所需的时间
  7. 除非首先在测试数据集上运行,否则永远不要在完整数据集上运行

测试数据集中包含什么?

应该具有最少的数据点以获得所需的输出

示例:

  1. 对于多年的时间序列,测试数据集应包含至少2年的数据点
  2. 对于空间趋势,具有多个网格点
  3. 如果数据集的部分包含特殊情况,请将这些作为额外的测试数据集
  4. 示例:分析海洋模型输出时,应有一个开阔海洋测试数据集和一个沿海测试数据集
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值