Unit testing 如何对Python数据帧进行单元测试

Unit testing 如何对Python数据帧进行单元测试,unit-testing,pandas,numpy,dataframe,Unit Testing,Pandas,Numpy,Dataframe,如何对python数据帧进行单元测试 我有一些函数,它们的输入和输出都是数据帧。几乎我所有的函数都能做到这一点。现在如果我想进行单元测试,最好的方法是什么?为每个函数创建一个新的数据帧(填充值)似乎有点费劲 你有什么资料可以给我参考吗?您应该为这些函数编写单元测试吗 我建议将值作为CSV写入docstrings(或单独的文件,如果它们很大),并使用pd.read\u CSV()解析它们。您也可以解析CSV的预期输出,并进行比较,或者使用df.to_CSV()写出CSV并对其进行区分。我认为为单元

如何对python数据帧进行单元测试

我有一些函数,它们的输入和输出都是数据帧。几乎我所有的函数都能做到这一点。现在如果我想进行单元测试,最好的方法是什么?为每个函数创建一个新的数据帧(填充值)似乎有点费劲


你有什么资料可以给我参考吗?您应该为这些函数编写单元测试吗

我建议将值作为CSV写入docstrings(或单独的文件,如果它们很大),并使用
pd.read\u CSV()
解析它们。您也可以解析CSV的预期输出,并进行比较,或者使用
df.to_CSV()
写出CSV并对其进行区分。

我认为为单元测试创建小数据帧并不困难

import pandas as pd
from nose.tools import assert_dict_equal

input = pd.DataFrame.from_dict({
    'field_1': [some, values],
    'field_2': [other, values]
})
expected = {
    'result': [...]
}
assert_dict_equal(expected, my_func(input).to_dict(), "oops, there's a bug...")

虽然Pandas的测试函数主要用于内部测试,但NumPy包含一组非常有用的测试函数,本文对此进行了说明:

这些函数比较NumPy数组,但您可以使用
value
属性获取数据帧下的数组。您可以定义一个简单的数据帧,并将函数返回的内容与预期内容进行比较

您可以使用的一种技术是为多个函数定义一组测试数据。这样,您就可以使用来定义该数据帧一次,并在多个测试中使用它


在资源方面,我发现这篇文章非常有用。我还在PyCon Canada 2016上做了一个关于数据分析测试的简短介绍:。

您可以使用pandas测试功能:

它将提供更多的灵活性,以不同的方式将您的结果与计算结果进行比较

例如:

df1=pd.DataFrame({'a':[1,2,3,4,5]})
df2=pd.DataFrame({'a':[6,7,8,9,10]})

expected_res=pd.Series([7,9,11,13,15])
pd.testing.assert_series_equal((df1['a']+df2['a']),expected_res,check_names=False)

有关更多详细信息,请参阅此

您可以使用
快照测试
并执行以下操作:

def test_something_works(快照):#快照是snapshottest中的pytest夹具
data\u frame=calc\u something\u和\u return\u pandas\u dataframe()
snapshot.assert\u match(data\u frame.to\u csv(index=False),“某个\u模块\u级别\u唯一\u名称\u用于\u快照”)
这将创建一个快照文件夹,其中的文件包含csv输出,您可以在代码更改时使用
--snapshot update
进行更新

它通过比较
数据帧
变量与保存到磁盘的内容来工作

值得一提的是,您的快照应该签入到源代码管理中。

Python包(我是该包的作者)旨在使单元或性能测试“创建新的数据帧(填充值)”变得容易

例如,如果您想要针对由浮点数和带有数字索引的字符串组成的数据帧进行测试,则可以使用紧凑的字符串声明来生成数据帧

>>ff.Fixture.to_frame('i(i,int)| v(float,str)| s(4,2)')。to_pandas()
0     1
34715 1930.40扎吉
-3648-1760.34 zJnC
91301 1857.34 zDdR
30205 1699.34祖武
>>>ff.固定装置至框架('i(i,int)| v(float,str)| s(8,3)')。至框架()
0     1        2
34715 1930.40扎吉694.30
-3648-1760.34 zJnC-72.96
91301 1857.34 zDdR 1826.02
30205 1699.34祖武604.10
54020 268.96 zKka 1080.40
129017 3511.58 zJXD 2580.34
35021 1175.36 zPAQ 700.42
1669242925.68 zyps 3338.48

如果您使用的是pytest,
pandasSnapshot
将非常有用

# use with pytest
import pandas as pd
from snapshottest_ext.dataframe import PandasSnapshot

def test_format(snapshot):
    df = pd.DataFrame([['a', 'b'], ['c', 'd']],
                      columns=['col 1', 'col 2'])
    snapshot.assert_match(PandasSnapshot(df))
一大缺点是快照不再可读。(将内容存储为csv更具可读性,但存在问题


PS:我是pytest snapshot extension的作者。

这是一个好主意,但是如果您的数据帧中有奇怪编码的数据,或者需要
文本评估的数组等,则处理
csv
文件可能会很烦人。如果她的代码结构正确,输入/预期的数据帧应该相当小,因此很容易o动态构造?我的结果也是一个数据帧。所以我应该创建另一个数据帧?在这种情况下,我不能使用assert_dict_equal?是的,这就是我调用
to_dict()的原因
关于函数的结果-因此我得到了一个
dict
,可以用建议的
nose
方法与
预期的
进行比较。@rkaleta:是的。但是,我的测试失败了,出现了错误,如断言错误:{'ins[20个字符]on':['TF000141124','TF000141124','TF00014[599个字符]0.0]}!={'ins[20个字符]on':{0:'TF000141124',1:'TF000141124',2:[716个字符]0.0}Diff的长度为3078个字符。请将self.maxDiff设置为“无”以查看它。:哦,有一个bug…@codegek123上述
预期的
代码只是一个示例-您必须根据需要进行修改。看起来预期的数据帧结构与实际的数据帧结构不匹配。看起来测试中的函数返回的数据帧为3 rows x 1列?那么预期的应该更像
expected={:,:,只是一个快速更新,Pytest Fixtures链接被破坏。可能他们移动了页面。这是他们的页面!谢谢@RyanStreur。我更新了链接。