NEP 26 — 缺失数据NEP总结与讨论#
- 作者:
Mark Wiebe <mwwiebe@gmail.com>, Nathaniel J. Smith <njs@pobox.com>
- 状态:
Deferred
- 类型:
标准轨道
- 创建时间:
2012-04-22
背景:此NEP旨在总结大量关于缺失数据功能性的讨论和提案(NEP 12 — NumPy中的缺失数据功能,NEP 24 — 缺失数据功能 - NEP 12的替代方案1,NEP 25 — 通过特殊数据类型支持NA)。
关于NumPy应如何处理缺失数据的争论由来已久且充满争议,存在许多预先存在的方法、要求和约定。已经提出了不止一个实现NumPy支持的方案,并且有一个可测试的实现已合并到NumPy的当前主分支中。大量的邮件和不同的观点使得感兴趣的各方难以理解问题并对NumPy的发展方向感到满意。
以下是我们(Mark和Nathaniel)的尝试,在一个地方总结问题、提案以及同意/不同意之处,以帮助社区朝着共识迈进。
NumPy开发者的难题#
在本讨论中,“缺失数据”是指可以索引的数组元素(例如,形状为(5,)的数组A中的A[3]),但在某种意义上没有值。
它不指压缩或稀疏存储技术,其中A[3]的值实际上并未存储在内存中,但仍有一个明确定义的值,例如0。
这仍然是模糊的,并且要创建一个实际的实现,有必要回答以下问题:
执行逐元素ufunc时会计算什么值。
执行归约时会计算什么值。
将元素标记为缺失时,该元素的存储是否会被覆盖。
产生NaN的计算是否会自动以与缺失值相同的方式处理。
是否通过占位符对象(例如,称为“NA”或“masked”)或通过单独的布尔数组与缺失值进行交互。
是否存在不能容纳缺失数组元素的数组对象。
从数据类型、掩码和其他构造的角度来看,(C和Python)API如何表达。
如果我们决定以多种方式回答其中一些问题,那么这就产生了是否需要多种系统的问题,如果是,它们应如何交互。
显然,存在一个非常大的缺失数据API空间可以实现。可能至少有一个用户,在某个地方,会发现任何可能的实现都是解决某个问题的最佳方案。另一方面,NumPy的许多强大功能和清晰性来自于少数正交的概念,例如跨步数组、灵活索引、广播和ufunc,我们希望保留这种简单性。
NumPy用户的一些主要群体对现有的缺失数据支持状况表示不满。特别是,numpy.ma组件或将浮点NaN用作缺失数据信号都不能完全满足这些用户的性能要求和易用性。R的例子,其中缺失数据通过NA占位符处理,并深度集成到所有计算中,是许多用户指向以表明他们想要的功能。
我们的问题是,如何选择一些增量添加项到NumPy中,以使一大类用户满意,并具有合理优雅、补充现有设计,并且我们有信心长期不会后悔。
现有技术#
因此,一个主要(也许是主要)问题是确定添加缺失数据支持的NumPy项目应该有多大的雄心,以及哪些类型的问题在范围内。让我们从“缺失数据”发挥作用的最容易理解的情况开始。
“统计缺失数据”#
在统计学、社会科学等领域,“缺失数据”是一个专业术语,指的是一种特定(但极其常见和重要)的情况:我们已尝试按照某种方案收集一些测量值,但其中一些测量值缺失了。例如,如果我们有一个列出个人身高、年龄和收入的表格,但某个人没有提供收入,那么我们需要一种方法来表示这种情况。
Person | Height | Age | Income
------------------------------
1 | 63 | 25 | 15000
2 | 58 | 32 | <missing>
3 | 71 | 45 | 30000
传统的方法是将该收入记录为(例如)“-99”,并在README中记录下来。然后,您必须记住专门检查和处理此类收入;如果您忘记了,您将得到表面上合理但完全不正确的结果,例如计算此数据集的平均收入为14967。如果您属于这些领域之一,那么这种缺失是例行公事且不可避免的,如果您使用“-99”方法,那么您必须在您进行的任何计算中显式地检查它。这显然是一种不愉快的生活方式。
为了方便起见,我们将这种情况称为“统计缺失数据”情况。(如前所述,从业者称之为“缺失数据”,并且如何处理它实际上是统计学的一个子领域;如果您搜索“缺失数据”,则所有引用都将是关于如何处理它。)NumPy不会进行自动插补或其他类似操作,但它可以提供一种标准方法来至少表示这种意义上的缺失数据,这将大有帮助。
如何实现这一目标的主要现有技术来自S/S+/R语言系列。他们的策略是,对于他们支持的每种类型,定义一个称为“NA”的特殊值。(对于int是INT_MAX,对于float是与任何其他NaN都可区分的特殊NaN值……)然后,他们安排在计算中,该值具有特殊的语义,我们将其称为“NA语义”。
NA语义#
NA语义的理念是,任何涉及NA值的计算都应该与如果我们知道正确的值会发生什么情况保持一致。
例如,假设我们要计算平均收入,我们该如何做?一种方法是忽略缺失条目,计算其余条目的平均值。我们得到(15000 + 30000)/2,即22500。
这个结果与发现第二个人收入是否一致?假设我们发现第二个人收入为50000。这意味着正确答案是(15000 + 50000 + 30000)/3,即31666.67,清楚地表明它不一致。因此,平均收入是NA,即一个我们无法计算其值的特定数字。
这促成了以下规则,这也是R实现NA的方式:
- 赋值
NA值被理解为代表特定的未知值,因此在赋值和其他基本数据操作方面应具有值类语义。不实际查看涉及值的代码,无论其中一些值是否缺失,都应该具有相同的效果。例如,可以编写
income[:] = income[np.argsort(height)]
以原地排序
income数组,并知道最矮的人的收入将排在最前面。事实证明,最矮的人的收入是未知的,因此数组应变为[NA, 15000, 30000],但这里NA性并没有什么特别之处。- 传播
在上面的例子中,我们得出结论,像
mean这样的操作在数据值为NA时应产生NA。如果您问我,“3加x是多少?”,那么我唯一的可能答案是“我不知道x是多少,所以我也不知道3+x是多少”。NA表示“我不知道”,所以3 + NA 是NA。这对于数据分析的安全性很重要:缺失数据通常需要特殊的处理才能保证正确性——您缺少信息的事实可能意味着您想要计算的内容实际上无法计算,并且有专门的书籍介绍了如何在各种情况下进行补偿。此外,很容易没有意识到您有缺失数据,并编写了假设您拥有所有数据的代码。此类代码不应默默地产生错误答案。
在布尔值的情况下,有一个重要的例外可以用来表征传播。考虑计算
v = np.any([False, False, NA, True])
如果严格传播,
v将变为NA。但是,无论我们将True还是False放入第三个数组位置,v都将获得True值。这个问题的答案是:“结果True是否与稍后发现缺失的值一致?”是,所以在这里不传播是合理的,而是返回True值。这正是R所做的。> any(c(F, F, NA, T)) [1] TRUE > any(c(F, F, NA, F)) [1] NA
- 其他
NaN和NA在概念上是不同的。0.0/0.0不是一个神秘的、未知的值——根据IEEE浮点运算,它被定义为NaN,即“非数字”。NA是数字(或字符串,或任何东西),只是未知的。另一个小但重要的区别是,在Python中,
if NaN: ...将NaN视为True(NaN是“真值”);但if NA: ...将是错误。在R中,所有归约操作都实现了一个替代语义,通过传递一个特殊参数(R中的
na.rm=TRUE)来激活。sum(a)表示“给我所有值的总和”(如果某些值是NA,则为NA);sum(a, na.rm=True)表示“给我所有非NA值的总和”。
其他现有技术#
一旦我们超越了“统计缺失数据”的案例,缺失数据的正确行为就变得不那么明确了。在许多情况下,特定的元素被单独挑选出来进行特殊处理或从计算中排除,而这些情况通常可以被概念化为某种意义上的“缺失数据”。
在图像处理中,通常使用单个图像加上一个或多个布尔掩码来(例如)复合图像的子集。正如Joe Harrington在邮件列表中指出的那样,在处理天文图像的背景下,也经常泛化为浮点值掩码或alpha通道,以表示“缺失”的程度。我们认为这超出了当前设计的范围,但这是一个重要的用例,理想情况下NumPy应该支持对这类数据的自然操作。
在R之后,numpy.ma可能是缺失数据相关API最成熟的经验来源。它的设计与R截然不同;它使用不同的语义——归约默认跳过掩码值,NaN转换为掩码——并且它通过单独的掩码使用不同的存储策略。虽然它似乎普遍被认为是次优的,但很难确定是因为API不成熟但基本良好,还是API根本上是错误的,或者是API很棒但代码应该更快,或者是什么。我们研究了一些用户以获得更好的了解。
Matplotlib可能是最著名的依赖numpy.ma的包。它似乎以两种方式使用它。一种是用户在将数据传递给绘图时指示哪些数据是缺失的。(也支持其他方式,例如,传递NaN值会得到相同的结果。)在这方面,matplotlib将np.ma.masked和NaN值与R的绘图例程处理NA和NaN值的方式相同。对于这些目的,matplotlib并不真正关心缺失数据使用什么语义或存储策略。
在内部,matplotlib使用numpy.ma数组来存储和传递单独计算的布尔掩码,这些掩码以廉价且非破坏性的方式包含每个输入数组的“有效性”信息。Mark从一些初步的代码审查中得到的印象是,大多数情况下它直接处理掩码数组的数据和掩码属性,而不是广泛使用numpy.ma的特定计算语义。因此,对于此用法,它们依赖于非破坏性掩码存储,但这并未说明需要什么语义。
Paul Hobson在邮件列表中发布了一些代码,使用numpy.ma存储污染物浓度测量值的数组。这里的掩码表示相应的数字是一个实际的测量值,还是一个太小而无法检测到的浓度的估计检测限。Nathaniel通过阅读这段代码的印象是,它也主要偏好使用MaskedArray的.data和.mask属性,而不是直接执行操作。
因此,这些例子清楚地表明,需要一种方便的方法来将数据数组和掩码数组(甚至浮点数组)捆绑在一起并“对齐”。但它们并没有告诉我们关于结果对象与ufunc及其类似物相关的语义。
语义、存储、API,哦我的!#
我们认为将用例、语义和存储清楚地分开很有用。用例是用户遇到的情况,无论NumPy做什么;它们是上一节的重点。当我们说语义时,我们指的是从Python级别查看不同操作的结果,而不考虑底层实现。
NA语义如上所述,由R使用。
1 + NA = NA
sum([1, 2, NA]) = NA
NA | False = NA
NA | True = True
当使用na.rm=TRUE或skipNA=True时,它会切换到
1 + NA = illegal # in R, only reductions take na.rm argument
sum([1, 2, NA], skipNA=True) = 3
还有关于我们称之为忽略语义的讨论。这些有点未定义。
sum([1, 2, IGNORED]) = 3
# Several options here:
1 + IGNORED = 1
# or
1 + IGNORED = <leaves output array untouched>
# or
1 + IGNORED = IGNORED
numpy.ma的语义是
sum([1, 2, masked]) = 3
1 + masked = masked
如果使用掩码实现了NA或忽略语义,那么可以选择在存储中对被赋值为缺失值的数组元素的值执行什么操作。有三种可能性:
保持内存不变(NEP中选择的选项)。
独立于掩码进行值计算(可能是Paul Hobson上述用例的最有用选项)。
将存储在缺失值后面的任何值复制到输出中(这是numpy.ma所做的。即使在
masked + masked的情况下,这也很模糊——在这种情况下,numpy.ma会复制左侧掩码值后面的存储值)。
当我们谈论存储时,我们指的是关于缺失值应该通过指定底层数据类型(位模式数据类型选项,如R中所用)的特定值来表示,还是通过使用存储在数据本身旁边的一个单独的掩码来表示的争论。
对于基于掩码的存储,还有一个重要的问题是访问掩码、修改掩码以及“查看”掩码的API是什么样的。
已提出的设计#
一种选择是直接复制R,通过实现一种机制,使得数据类型可以安排特定的位模式被赋予NA语义。
一种选择是紧密复制numpy.ma,但实现更优化的实现。(或者仅仅是优化现有实现。)
一种选择是NEP12中描述的那种,它有一个基于掩码的缺失数据实现。这个系统大致是
既有位模式又有掩码的缺失数据,并且两者都具有相同的可互操作的NA语义。
通过将np.NA或值赋给数组元素来修改掩码。查看掩码或取消掩码的方法是保持数组的视图,该视图共享数据指针但不共享掩码指针。
Mark希望添加一种直接访问和操作掩码的方法,以补充这种基于视图的API。
如果一个数组同时具有位模式数据类型和掩码,那么将np.NA赋值会写入掩码,而不是数组本身。向支持两者的数组写入位模式NA需要通过“查看掩码下方”来访问数据。
另一种选择是NEP24中描述的那种,即为“统计缺失数据”用例实现具有NA语义的位模式数据类型,并且还为具有忽略语义的掩码数组实现一个完全独立的API,所有掩码操作都通过.mask属性显式完成。
另一种选择是定义一个极简的对齐数组容器,该容器保存多个数组,并可用于将它们一起传递。它支持索引(以帮助解决希望同时对多个数组进行子集操作而不使其失对齐的常见问题),但所有算术等都将通过属性直接访问底层数组完成。上面的“现有技术”讨论表明,类似这样的东西保存.data和.mask数组实际上可能解决了许多人的问题,而无需对NumPy进行任何重大的架构更改。这类似于结构化数组,但每个字段都存储在单独的数组中,而不是打包在一起。
一些人建议应该有一个单一的系统,具有多种缺失值,每种值具有不同的语义,例如,一个具有NA语义的MISSING值,以及一个具有忽略语义的单独的IGNORED值。
这些选项并非都必然互斥。
辩论#
我们都怀疑将忽略语义作为默认的缺失数据行为。Nathaniel喜欢NA语义,因为他对“统计缺失数据”用例最感兴趣,而NA语义正是为此而生的。Mark对这个用例不那么感兴趣,但他喜欢NA计算抽象,因为它在所有情况下都是明确且定义良好的,并且有大量的现有经验可借鉴。
Nathaniel的总体看法
“统计缺失数据”用例清晰且令人信服;其他用例当然值得我们关注,但很难确切地说它们是什么,甚至支持它们的最佳方法是否是扩展ndarray对象。
“统计缺失数据”用例最好由R风格的系统来满足,该系统使用位模式存储来实现NA语义。位模式存储对该用例的主要优点是它避免了存储和检查掩码的额外内存和速度开销(特别是对于浮点数据,其中一些NaN技巧允许我们有效地硬件加速大多数NA操作)。仅这些考虑因素就使得基于掩码的实现对许多NA用户来说是不可接受的,特别是在神经科学(内存紧张)或金融建模(毫秒至关重要)等领域。此外,位模式方法在概念上不那么令人困惑(例如,赋值确实就是赋值,幕后没有魔法),并且可以通过rpy2实现与R的内存兼容性。位模式方法的主要缺点是需要放弃一个值来表示NA,但这对于最重要的数据类型(float、bool、strings、enums、objects)来说不是问题;实际上,只有整数会受到影响。即使对于整数,放弃一个值对于统计问题来说也无关紧要。(尽管占领华尔街,但没有人收入是2**63 - 1。即使有,我们也会切换到浮点数以避免溢出。)
添加新的数据类型需要与ufunc和类型转换机制进行一些协作,但不需要NumPy的任何架构更改或违反NumPy当前的正交性。
他从邮件列表讨论中(特别是“我们可以同意什么?”主题)得出印象,许多numpy.ma用户特别喜欢掩码存储、通过API轻松访问掩码以及忽略语义的组合。他可能错了,当然。但他不记得看到Mark以外的任何人提倡掩码存储和NA语义的特定组合,这让他感到不安。
此外,他个人不太喜欢在Python层面拥有两个几乎完全相同的接口的想法。虽然很可能有人希望暂时假装某些数据是“统计缺失数据”而不复制他们的数组,但他们是否比那些希望同时使用位模式和掩码以便区分目的的人多,这一点并不清楚。老实说,他希望能够选择忽略掩码并坚持使用位模式,如果它们紧密耦合在API中,这是不可能的。所以他会说,在这个NEP设计的这个方面是优势还是劣势,陪审团还在评判中。(当然,他从未听说过任何R用户抱怨他们真的很希望有一个选择来做出不同的权衡。)
R的NA支持是一个主要功能,其目标受众认为它是与其他平台(如Matlab或Python)相比的一个引人注目的优势。没有平台支持,处理统计缺失数据非常痛苦。
相比之下,我们对于需要基于掩码的实现的用例显然有更多的不确定性,而且似乎人们在现在被迫满足于使用NumPy出色的基于掩码的索引、新的where=支持,甚至numpy.ma时,也不会遭受太大的痛苦。
因此,具有NA语义的位模式似乎满足了让一大类用户满意、以优雅的方式、适合原始设计,并且我们可以有把握地确定我们足够了解问题和用例,以至于我们长期都会对它们满意。但目前还没有基于掩码的存储方案能够做到这一点。
Mark的总体看法
默认使用NA语义作为缺失数据的想法,受到“统计缺失数据”问题的启发,优于所有其他被考虑的默认行为。这同样适用于位模式和掩码方法。
为了让NA风格的功能得到所有NumPy功能以及最终所有第三方库的正确支持,它需要进入核心。如何正确有效地处理缺失数据因算法而异,如果需要思考才能完全支持NumPy,NA支持将更广泛、更高质量。
同时,提供两种不同的缺失数据接口,一种用于掩码,一种用于位模式,需要NumPy开发人员和第三方NumPy插件开发人员分别考虑在两种情况下该做什么,并进行另外两次代码实现。这增加了他们的工作难度,并可能导致缺失数据支持不一致。
通过相同的C和Python编程接口提供同时处理掩码和位模式的能力,使缺失数据支持与NumPy的所有其他功能保持清晰的正交性。
内存使用、性能、正确性和灵活性之间存在许多权衡。提供对这两种方法的支持,使用户可以选择最符合他们思维方式的方法,或者具有最匹配其用例的特征。通过相同的接口提供它们,还允许他们轻松尝试这两种方法,并为他们的程序选择性能更好或内存使用最少的方法。
内存使用
使用位模式,存储包含一些NA的单个数组时使用的内存更少。
使用掩码,存储多个除NA位置不同之外完全相同的数组时使用的内存更少。(在这种情况下,可以重复使用一个数据数组和多个掩码数组;位模式NA需要复制整个数据数组。)
性能
使用位模式,浮点类型可以使用本机硬件操作,行为接近正确。要实现完全正确的浮点行为以及其他类型,必须编写专门测试与缺失数据位模式相等的代码。
使用掩码,始终存在访问掩码内存和测试其真值的开销。目前存在的实现没有性能调整,因此只能判断最低性能水平。最佳的基于掩码的代码通常比最佳的基于位模式的代码慢。
正确性
位模式整数类型必须牺牲一个有效值来表示NA。对于较大的整数类型,有论点认为这可以接受,但对于8位类型,没有合理的选择。在浮点情况下,如果选择本机浮点操作的性能,则存在一个小的不一致,即NaN+NA和NA+NaN是不同的。
使用掩码,在所有情况下都能正确工作。
通用性
位模式方法只能在有一个特定值可以从数据类型中放弃的情况下才能以完全通用的方式工作。对于IEEE浮点数,NaN是一个显而易见的选择,对于表示为字节的布尔值,有许多选择。对于整数,使用此方法必须牺牲一个有效值。第三方数据类型集成到NumPy中也必须选择位模式,这可能并不总是可行。
掩码方法可与所有数据类型通用。
前进的建议#
Nathaniel认为我们应该
继续实现位模式NA。
不在核心中实现掩码数组——或者至少,暂时不。相反,我们应该专注于弄清楚如何实现它们(out-of-core),以便人们可以尝试不同的方法,而无需我们承诺任何一种方法。这样新的原型就可以比NumPy的发布周期更快地发布。而且,如果我们希望NumPy在不分叉的情况下继续发展,我们无论如何都必须弄清楚如何从外部实验这些变化,现在就这么做吧。现有代码可以保留在主分支中,被禁用,或者在自己的分支中——一旦我们知道我们在做什么,它仍然在那里。
Mark认为我们应该
现有代码应保持不变,并添加一个全局运行时实验标志,默认情况下禁用NA支持。
更详细的此建议理由如下:
NumPy 主版本中目前有一个稳固的初步 NA-mask 实现。此实现已针对 scipy 和其他第三方软件包进行了广泛测试,并且已在主版本中稳定存在了相当长一段时间。
此实现与核心深度集成,提供了一个可以像 R 的 NA 支持那样使用的接口。它为 R 的 NA 支持提供了一个引人注目的、用户友好的解决方案。
缺失数据 NEP 提供了一个关于添加基于位模式的 NA 数据类型支持的计划,该计划将通过相同的接口运行,但允许 R 所做的相同的性能/正确性权衡。
让用户非常容易地试用此实现,该实现具有合理的功能覆盖范围和性能特征,这是获得关于 NumPy 缺失数据支持应该是什么样子的更具体反馈的最佳方式。
由于其初步状态,现有实现将在 NumPy 文档中标记为实验性的。最好将其一直标记为实验性的,直到它更加完善,例如支持 struct 和 array 数据类型,以及更完整的 NumPy 操作集。
我认为代码应该保持原样,除了添加一个运行时全局 NumPy 标志,也许是 numpy.experimental.maskna,它默认为 False,并且可以切换为 True。在其默认状态下,任何 NA 功能的使用都会引发“ExperimentalError”异常,这是一项措施,可以防止它被意外使用,并非常清楚地传达其实验性状态。
ABI 问题在 1.x 系列版本中似乎非常棘手,难以有效处理,但我相信通过在 2.0 版本中进行适当的实现隐藏,进化软件以支持已经讨论过的各种其他 ABI 想法是可行的。这是我最喜欢的方法。
Nathaniel 在回复中指出,他实际上并不反对在主 numpy 分发版中发布实验性 API,*前提是*我们小心确保它们不会“泄露”出去,让我们受困于它们。原则上,某种“这违反了您的保修”的全局标志可以是一种做到这一点的方法。(事实上,这对于他倾向的那些改变也可能是一个有用的策略,即添加最小的钩子以使我们能够更容易地构建原型 - 我们可以有一些“仅限快速原型设计”的钩子,让原型化的黑客能够比我们原本准备支持的更深入地访问 NumPy 的内部。)
但是,他想指出两点。首先,关于 NEP 设计,我们似乎仍然有一些基本问题需要回答,例如掩码应该具有 NA 语义还是忽略语义,并且已经有计划对 NEP 掩码的暴露和访问方式进行重大更改。所以他不确定通过请求对 NEP 代码当前状态的反馈能学到什么。
其次,考虑到它们可能(轻微)导致 ABI 问题的担忧,不清楚我们是否真的能阻止它们泄露。(他也期待 2.0,但我们还没有到那里。)所以也许最好它们根本就不存在于 C API 中,而测试人员所需的那些周折反而会是,‘我们包含了一个可以访问的、糟糕的纯 Python 原型,可以通过输入“import numpy.experimental.donttrythisathome.NEP”来访问,并欢迎反馈’?
如果是这样,那么他应该提到他确实实现了 NEP API 的一个非常粗糙、纯 Python 的实现,该实现适用于 NumPy 1.6.1。这主要是作为一项实验,看看这种原型设计有多可行,并测试一个可能的 ufunc 覆盖机制,但如果有兴趣,该模块在此处可用:njsmith/numpyNEP
它通过了 maskna 测试套件,在顶部的大注释中描述了一些小问题。
Mark 回复:
我同意在向 NumPy 添加新功能时要小心,但我同样相信项目必须有前进的发展动力。像 NumPy 这样的项目需要开发人员编写代码才能进步,而阻碍编写代码的障碍会阻止现有开发人员做出更多贡献,并可能吓跑那些考虑加入的开发人员。
所有软件项目,无论是开源还是闭源,都必须在短期实用性和长期规划之间取得平衡。在缺失数据开发方面,有一个短期资源承诺来解决这个问题,这个问题规模非常庞大。如果获得对 NumPy 的一项贡献以具体推进解决方案的可能性不高,我预计那些有兴趣进行此类工作的人和公司将更难证明其资源承诺是合理的。对于一个对许多其他库都至关重要的项目,仅依赖无私志愿者的善意意味着 NumPy 可能更容易被另一个项目超越。
在存在争议的现有 NA 贡献方面,我们如何解决这个分歧代表了一个关于 NumPy 的开发人员、贡献者和用户应该如何互动的决定。如果我们创建一个描述争议解决过程的文档,我们如何设计它,使其不会给开发人员带来巨大的负担和过度的不确定性,从而阻止他们富有成效地贡献代码?
如果我们采取编写包含这种争议解决机制的决策过程的路线,我认为其核心应该是潜在贡献者和开发人员可以遵循的路线图,以获得对 NumPy 的影响力。NumPy 开发需要广泛的支持,而不仅仅是代码贡献,将项目中的影响力与贡献联系起来,在我看来,将是鼓励人们承担诸如错误分类/管理、持续集成/构建服务器管理以及满足项目需求的众多其他任务的好方法。没有任何特定的精英、民主、共识驱动的系统能让所有人满意,但围绕治理和流程的激烈讨论表明,需要一些比当前现状更正式的东西。
总之,我希望 NumPy 项目优先向更灵活和模块化的 ABI/API 发展,同时保持强大的向后兼容性约束和个人、大学和公司希望贡献的功能添加。我认为将 NA 代码保留在 1.7 版中,并增加一个需要通过实验性标志启用的额外措施,不会带来长期 ABI 问题的风险。我看到的更大风险是持续缺乏开发人员为项目做出贡献,并且我相信撤回这些代码因为这些担忧会带来降低开发人员贡献的风险。
参考文献和脚注#
NEP 12 — NumPy 中的缺失数据功能 描述了 Mark 的 NA 语义/掩码实现/基于视图的掩码处理 API。
NEP 24 — 缺失数据功能 - NEP 12 的替代方案 1(“alterNEP”)是 Nathaniel 最初尝试将 MISSING 和 IGNORED 处理分离为位模式与掩码,尽管他目前会对该提案进行很多更改。
NEP 25 — 通过特殊数据类型支持 NA(“miniNEP 2”)是 Nathaniel 后来尝试勾勒出 NA 数据类型实现策略。
进一步的讨论概述页面可在以下网址找到:njsmith/numpy
版权#
本文档已置于公共领域。