【问题标题】:How to troubleshoot pandas bug/feature?如何解决 pandas 错误/功能?
【发布时间】:2013-01-28 13:29:18
【问题描述】:

我有一个熊猫DataFrame,是这样创建的:

import pandas as pd
wb = pd.io.parsers.ExcelFile('/path/to/data.xlsx')
df = wb.parse(wb.sheet_names[0])

生成的数据框有大约十二列,所有列的长度完全相同(大约 150K)。

对于大多数列,以下操作几乎是瞬间完成的

aset = set(df.acolumn)

但是对于某些列,同样的操作,例如

aset = set(df.weirdcolumn)

需要 > 10 分钟! (或者更确切地说,操作在 10 分钟超时期限到期之前无法完成。)相同数量的元素!

还是很陌生:

In [106]: set([type(c) for c in df.weirdcolumn])
Out[106]: set([numpy.float64])

In [107]: df.weirdcolumn.value_counts()
Out[107]: []

看来专栏的内容都是nans

In [118]: all(np.isnan(df.weirdcolumn.values))
Out[118]: True

但这并不能解释前面提到的减速,因为下面的操作只需要几秒钟:

In [121]: set([np.nan for _ in range(len(data))])
Out[121]: set([nan])

我已经没有办法找出上述大幅放缓的原因。欢迎提出建议。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    关于 nans 的一个奇怪的事情是它们的比较不相等。这意味着将为集合单独插入“不同”的 nan 对象:

    >>> float('nan') == float('nan')
    False
    >>> float('nan') is float('nan')
    False
    >>> len(set([float('nan') for _ in range(1000)]))
    1000
    

    这不会发生在您对 np.nan 的测试中,因为它一遍又一遍地是同一个对象:

    >>> np.nan == np.nan
    False
    >>> np.nan is np.nan
    True
    >>> len(set([np.nan for _ in range(1000)]))
    1
    

    这可能是你的问题;您正在制作一个包含 150,000 个元素的集合,其中每个元素 具有完全相同的哈希 (hash(float('nan')) == 0)。这意味着将一个新的 nan 插入到已经有 n nans 的集合中至少需要 O(n) 时间,因此构建一组 N nans 至少需要 O(N^2) 时间。 150k^​​2...很大。

    所以是的,nans 很烂。你可以通过做类似的事情来解决这个问题

    nan_idx = np.isnan(df.weirdcolumn)
    s = set(df.weirdcolumn[~nan_idx])
    if np.any(nan_idx):
        s.add(np.nan)
    

    【讨论】:

    • 多么奇特。这会杀死你的表现。由于每个nan 都会散列到相同的值,因此这是散列表中冲突解决的绝对最坏情况。我想知道这样的东西是否可以在 python 中被用于恶意目的......
    • np.nan 没有在集合中重复出现,这有点奇怪。根据hashable 的词汇表索引,为了使对象可散列,所有检查的是__eq__(或__cmp__)和__hash__
    • The docs say: "对于列表、元组、集合、frozenset、dict 或 collections.deque 等容器类型,表达式 x in y 等价于 any(x is e or x == e for e in y)。"大概它会检查 is 以缩短 == 测试,因为除了 nan a is b 之外的大多数东西都暗示 a == b,但这似乎是它们不是的情况下语义的一部分。
    • 有趣。该行不在我通常阅读的 2.7 文档中。
    猜你喜欢
    • 2020-03-27
    • 2018-10-06
    • 2021-01-25
    • 2023-03-23
    • 2020-04-27
    • 2020-03-19
    • 2021-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多