【问题标题】:Python list comprehension for NumpyNumpy 的 Python 列表理解
【发布时间】:2012-01-01 21:53:26
【问题描述】:

我正在 Numpy 中寻找列表理解方法或类似方法,以消除对 for 循环的使用,例如。 index_values 是一个 Python 字典列表(每个列表包含不同数量的索引值),s 是一个 numpy 向量:

for i in range(33):
    s[index_values[i]] += 4.1

有没有一种方法可以消除for循环?

【问题讨论】:

  • 我认为没有比使用 python 的列表推导更通用的方法了......但如果你正在做一些特定的事情,比如特定的数学运算,可能有一种方法。你想做什么?

标签: python for-loop numpy list-comprehension


【解决方案1】:

我不完全理解 index_values 是什么类型的对象。但如果它是ndarray,或者可以转换为ndarray,你可以这样做:

>>> s = numpy.arange(20)
>>> index_values = (numpy.random.random((3, 3)) * 20).astype('i')
>>> s[index_values] = 4
>>> s
array([ 0,  1,  4,  4,  4,  5,  6,  4,  8,  4,  4, 11, 12, 
       13,  4, 15,  4,  4,  4, 19])

编辑:但在这种情况下似乎行不通。根据您的编辑和 cmets,我认为这是一种可能适合您的方法。具有不同长度的随机列表...

>>> index_values = [list(range(x, x + random.randrange(1, 5)))
...                 for x in [random.randrange(0,50) for y in range(33)]]

...转换成数组并不难:

>>> index_value_array = numpy.fromiter(itertools.chain(*index_values), 
                                       dtype='i')

如果您知道数组的长度,请指定count 以获得更好的性能:

>>> index_value_array = numpy.fromiter(itertools.chain(*index_values), 
                                       dtype='i', count=83)

正如 Robert Kern 所指出的,由于您的编辑表明您需要类似直方图的行为,因此简单的索引是行不通的。所以使用numpy.histogram:

>>> hist = numpy.histogram(index_value_array, bins=range(0, 51))

histogram 实际上是为浮点直方图构建的。这意味着 bin 必须比预期的大一些,因为最后一个值包含在最后一个 bin 中,因此如果我们使用更直观的 range(0, 50),48 和 49 将在同一个 bin 中。结果是一个包含 n 个计数数组和一个 n + 1 个 bin 边界数组的元组:

>>> hist
(array([2, 2, 1, 2, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 5, 5, 5, 3, 3, 
        3, 3, 3, 2, 1, 0, 2, 3, 3, 1, 0, 2, 3, 2, 2, 2, 3, 2, 1, 1, 2, 2, 
        2, 0, 0, 0, 1, 0]), 
 array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
        34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]))

现在我们可以将计数放大 4.1 倍并执行向量加法:

>>> s = numpy.arange(50, dtype='f')
>>> hist[0] * 4.1 + s
array([  8.2,   9.2,   6.1,  11.2,   8.1,   5. ,   6. ,   7. ,  12.1,
        13.1,  14.1,  15.1,  16.1,  13. ,  18.1,  19.1,  20.1,  37.5,
        38.5,  39.5,  32.3,  33.3,  34.3,  35.3,  36.3,  33.2,  30.1,
        27. ,  36.2,  41.3,  42.3,  35.1,  32. ,  41.2,  46.3,  43.2,
        44.2,  45.2,  50.3,  47.2,  44.1,  45.1,  50.2,  51.2,  52.2,
        45. ,  46. ,  47. ,  52.1,  49. ])

我不知道这是否适合您的目的,但这似乎是一个不错的方法,并且应该以接近 c 的速度发生,因为它仅使用 numpyitertools

【讨论】:

  • 这是 numpy 数组的正确答案。唯一需要注意的是将其扩展到增强分配。当index_values 中有重复时,扩充的赋值不会像在完整的 for 循环中那样重复发生(原因很复杂)。因此,您不能像许多人试图做的那样,使用这种索引来制作临时直方图。
  • index_values 是一个 Python 字典列表,例如。 [[3, 6, 7], [5, 7, 11, 25, 99], [8, 45]]。 index_values 不能是 ndarray - 抱歉!
  • @dbv,我认为让我感到困惑的是“列表的字典列表”。我不知道什么是“字典列表”。您的意思是简单的列表字典吗?如果是这样,你为什么要使用整数来索引它?为什么不只使用列表列表?可以将列表列表传递给numpy.array 以生成相应形状的ndarray,如下所示:numpy.array([[1, 2, 3], [1, 2, 3]])。如果你必须使用字典,你至少可以通过这样的理解来提高速度:numpy.array([d[i] for i in range(2)]).
  • @dev 使用 ndarray 来索引 s 几乎肯定是要走的路,让我们知道为什么你认为你不能将 index_values 变成 ndarray,也许我们可以想出一个修复方法。 Robert Kern 提出的问题也有一个相对简单的解决方法,如果它与您的情况相关,请告诉我,我会发布代码。
  • 伙计们,我将在今天晚些时候删除这个问题并重新制定一个新问题。谢谢你,希望在另一边见到你。
【解决方案2】:

怎么样:

s[reduce(lambda x,y: x+y, [index_values[x] for x in range(33)], [])] = 4.1

【讨论】:

  • 见 Tadeck 下的评论。谢谢!
  • 在塔德克? :?目前看不到任何 Tadek :) (人们不断删除他们的答案,很难跟踪!)
  • 是的,刚刚看到@Tadeck 的答案已被删除。我已经编辑了上面的原始问题以显示 Numpy 向量 s 已就地更新。
  • 是的,当然。我对@Tadeck 回答的评论是关于他对理解和过滤器的使用,而不是对最终结果的评论。当然我知道你打算修改s的部分内容,而不是创建一个新数组:)
  • reduce 函数正在累积 index_values[x] 中的值。说 index_value[x] = [4, 7, 9, 11, 13],那么我们想要 s[[4, 7, 9, 11, 13]] = s[[4, 7, 9, 11, 13]] + 4.1 即。 s[4] += 4.1, s[7] += 4.1, etc. for x in range(33).
猜你喜欢
  • 2021-11-28
  • 1970-01-01
  • 2016-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
  • 2018-05-02
相关资源
最近更新 更多