首页 > 解决方案 > 不可靠的 mylist.count(nan) 并且没有警告

问题描述

我有一个值列表。某些值已损坏并表示为“nan”。在处理了一些数据之后,“nan”按预期和预期传播。

在操纵的数据集中,我想找到无用值的数量。直觉上,我使用了 method .count(nan),但令我惊讶的是,在没有警告的情况下,只计算了“未经处理的”nans。

我在 docs.python math.nan中没有立即找到答案,并且list.count(x) 方法 的文档不是很精确:

返回 x 在列表中出现的次数。

from math import nan, isnan

list1 = [nan]

myitem1 = list1[0]
myitem2 = list1[0] + 1 # common operation: extract a value from a list
print(myitem2) # nan: looks like nan
print(isnan(myitem2)) # True: is nan

list2 = [1, nan, myitem1, myitem2]
count1 = list2.count(nan)
count2 = sum(isnan(e) for e in list2)
print(count1, count2)  # 2, 3: doesn't always count as nan

标签: pythonlistcountnan

解决方案


虽然myitem2有一个 NaN 值,但它是一个不同于 的float实例math.nan,因为+运算符总是返回一个新对象,即使它具有相同的值。

list2.count(nan)只返回列表中包含的次数math.nan

它有助于查看对象 ID(示例值,每次运行代码时它们都不同):

>>> id(nan)
140305278866152
>>> id(myitem2)
140305278866176
>>> [id(x) for x in list2]
[9079008, 140305278866152, 140305278866152, 140305278866176]
#   1           nan              nan            myitem2

现在你可能会问,

>>> a = 5.0
>>> b = a + 0
>>> list3 = [a, b]
>>> id(a)
140133123191696
>>> id(b)
140133123191504
>>> [id(x) for x in list3]
[140133123191696, 140133123191504]
>>> list3.count(a)
2

为什么这不返回 1,因为a两个b不同的对象具有相同的值?

解释是,count实际上首先将每个列表项与它的参数按身份进行比较,但如果不同,则按进行比较。

我没有找到指定的位置,但这里是 CPython实现(我添加的评论):

static PyObject *
list_count(PyListObject *self, PyObject *value)
{
    Py_ssize_t count = 0;
    Py_ssize_t i;

    for (i = 0; i < Py_SIZE(self); i++) {
        PyObject *obj = self->ob_item[i];
        // comparison by identity
        if (obj == value) {
           count++;
           continue;
        }
        Py_INCREF(obj);
        // comparison by value
        int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
        Py_DECREF(obj);
        if (cmp > 0)
            count++;
        else if (cmp < 0)
            return NULL;
    }
    return PyLong_FromSsize_t(count);
}

最后,您需要知道按将任何内容与 NaN 进行比较总是返回“不等于”,即使另一个值也是 NaN(我也没有找到为 Python 指定的位置,但请参阅Why does compare to nan yield False (Python)?以及对于 IEEE754 NaN 值返回 false 的所有比较的基本原理是什么?)。

这就是为什么myitem2不包含在 中.count(nan),而是b包含在 中的原因.count(a)


推荐阅读