【问题标题】:Replacing Nones in a python array with zeroes用零替换python数组中的无
【发布时间】:2012-12-27 20:29:39
【问题描述】:

我刚刚使用命令将两个长度不等的数组连接在一起:

allorders = map(None,todayorders, lastyearorders)

在今天的订单没有值的地方给出“无”(因为今天的订单数组没有那么长)。

但是,当我尝试将 allorders 数组传递到 matplotlib 条形图中时:

 p10= plt.bar(ind, allorders[9],   width, color='#0000DD', bottom=allorders[8])

..我收到以下错误:

TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType'

那么,matplotlib 有没有办法不接受任何数据类型?如果没有,如何在我的 allorders 数组中用零替换“Nones”?

如果可以,因为我是 Python 新手(来自 R 社区),请提供从头到尾的详细代码,我可以使用/测试。

【问题讨论】:

  • 澄清一下:你想用零替换 all Nones,还是仅仅因为它更短而添加到 todayorders 末尾的那些?
  • 现在我更好地理解了这个问题,不要使用map(或zipizip_longest或任何其他非numpy处理lists和/或的函数一般可迭代)与numpy.array 对象,如果你能避免的话。

标签: python numpy matplotlib nonetype map-function


【解决方案1】:

使用列表推导:

allorders = [i if i[0] is not None else (0, i[1]) for i in allorders]

【讨论】:

  • @abarnert:您的生成器将无法工作,因为它是将None 值添加到输出的map(),而不是todayorders 本身包含任何None 值。跨度>
  • 这是对上述问题的一个很好的答案,但实际上对于 OP 实际想要的东西并不是很好,即有效地堆叠两个不同形状的 numpy.array 对象。将它们转换为列表、压缩列表并转换回来是可行的,但这是个坏主意。 (我的答案也是如此,直到我重写了大部分......)
【解决方案2】:

使用 numpy:

import numpy as np
allorders = np.array(allorders)

由于 Nones,这会创建一个对象数组。我们可以用零替换它们:

allorders[allorders == None] = 0

然后将数组转换为正确的类型:

allorders.astype(int)

【讨论】:

    【解决方案3】:

    因为听起来您希望这一切都在numpy 中,所以您的问题的直接答案实际上只是一个旁白,而正确 答案直到“当然……”段落。

    如果您考虑一下,您使用mapNone 第一个参数作为zip_longest,因为Python 没有zip_longest。但它确实有一个,在itertools——它允许你指定一个自定义的fillvalue。所以,您可以通过izip_longest 一步完成这一切:

    >>> import itertools
    >>> todayorders = [1, 2]
    >>> lastyearorders = [1, 2, 3]
    >>> allorders = itertools.izip_longest(todayorders, lastyearorders, fillvalue=0)
    >>> list(allorders)
    [(1, 1), (2, 2), (0, 3)]
    

    这仅填充0 用于显示为较短列表的额外值的Nones;如果您想用0 替换每个 None,您必须按照Martijn Pieters 的方式进行。但我认为这就是你想要的。

    另外,请注意末尾的list(allorders)izip_longest,与itertools 中的大多数内容一样,返回一个迭代器,而不是list。或者,用您可能更熟悉的术语来说,它返回一个“惰性”序列而不是“严格”序列。如果您只是要迭代结果,那实际上会更好,但是如果您需要将它与需要 list 的某些功能一起使用(例如以人类可读的形式打印出来 - 或访问 allorders[9],如在您的示例中),您需要先显式转换它。

    如果您真的想要numpy.array 而不是list,您可以直接到达那里,而无需先通过list。 (如果您只想使用matplotlib 它,您可能确实想要array。)最明确的方法是使用np.fromiter(allorders) 而不是list(allorders) .您可能想传递一个明确的dtype=int(或任何合适的)。而且,如果您知道大小(您知道它是 max(len(todayorders), len(lastyearorders))),在某些情况下,传递显式 count 也会更快或更简单。

    当然,如果numpy 中的任何一个听起来很吸引人,您可能首先应该留在numpy,而不是使用mapizip_longest

    >>> todayorders.resize(lastyearorders.shape)
    >>> allorders = np.vstack(todayorders, lastyearorders).transpose()
    

    不幸的是,todayorders 发生了变异,据我所知,等效的不可变函数 numpy.resize 并没有给你任何“零扩展”的方法,而是重复这些值。希望我错了,有人会建议简单的方法,但否则,你必须明确地这样做:

    >>> extrazeros = np.zeros(len(lastyearorders) - len(todayorders), dtype=int)
    >>> allorders = np.vstack(np.concatenate((todayorders, extrazeros)), lastyearorders)
    >>> allorders = allorders.transpose()
    array([[ 1,  1],
           [ 2,  2],
           [ 0,  3]])
    

    当然,如果你做了很多这样的事情,我会编写一个 zeroextend 函数,它接受一对数组并扩展一个以匹配另一个(或者,如果你不只是处理一维,扩展在每个轴上缩短一个以制作另一个)。

    无论如何,除了比使用mapizip_longest 等更快和使用更少的临时内存之外,这也意味着你最终得到了一个正确的数组 dtype (int而不是object)——这意味着你的结果也会使用更少的长期记忆,从那时起你所做的一切也会更快并且使用更少的临时记忆。

    为了完整性:可以让 pyplot 处理 None 值,但我认为这不是您想要的。例如,您可以传递一个Transform 对象,其transform 方法将None 转换为0。但这实际上与 Martijn Pieters 的答案相同,但更加冗长,除非您需要绘制大量此类数组,否则根本没有任何优势。

    【讨论】:

    • 谢谢——但是,如何将迭代器 allorders 转换回数组?如果我以当前形式传递 matplotlib allorders,我得到: TypeError: 'itertools.izip_longest' object has no attribute 'getitem'
    • @user1784454:如果您想恢复原来的list,请阅读以“另外,请注意...”开头的段落,它准确地解释了您的要求。如果您想将其转换为 numpy array(您可能想要),请参阅 fromiter
    • 酷——是的,我需要它是一个 numpy 数组——我会看看 fromiter。
    • @user1784454:在这种情况下,请参阅我的更新答案。如果你可以在numpy 中做你想做的事情,那么走出numpy(尤其是list,还有一个迭代器)通常是个坏主意。因此,请使用 vstack 而不是 mapizip_longest
    猜你喜欢
    • 2013-06-08
    • 2019-04-19
    • 1970-01-01
    • 2015-03-02
    • 2020-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多