如何将 Numpy 格式的列表转换为 python

Posted

技术标签:

【中文标题】如何将 Numpy 格式的列表转换为 python【英文标题】:How to convert lists in Numpy format to python 【发布时间】:2017-02-13 16:38:33 【问题描述】:

我有一个 Numpy 矩阵,我正在使用 for 循环遍历矩阵中的每一行,我想从每一行中找到第一个非零值

我已经找到了一种方法来在这里找到第一个非零值,但它需要一个列表作为它的参数:

for row in matrix:
    val = next((i for i, x in enumerate(row) if x), None)

val 总是返回 0

我还尝试在计算“val”之前将该行转换为列表

rowList = row.tolist()

但这也返回了相同的值

当我打印任一值时,输出包含列表周围的 2 个括号,这可能有影响吗?

即。

[[0, 0, 1, 2, 3]]

即使在我将行转换为列表后也会发生这种情况

有什么方法可以将每一行转换为一个列表,这样我就可以找到第一个非零值的索引,还是有另一种更简单的方法来做到这一点?

【问题讨论】:

你不可能使用np.matrix 类(而不是np.array)?如果是这样,请尝试将.A 附加到matrix。这将转换为np.array,其行为往往更符合人们的预期。 【参考方案1】:

您的next 表达有效:

In [793]: [next((i for i,x in enumerate(row) if x),None) for row in np.eye(10)]
Out[793]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

好的,这给出了第一个非零的索引,但在我的示例中,这比 1 值更有趣。

In [801]: [row.nonzero()[0][0] for row in np.eye(10)]
Out[801]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

但是如果数组有一行全为0,比如in

arr =np.diag(np.arange(0,20,2))

nonzero 版本引发错误。需要对nonzero返回空列表的情况敏感。

要从idx 列表中获取值,请使用

arr[np.arange(len(idx)), idx]

时间

对于大型对角线数组,nonzero 明显更快:

In [822]: arr =np.diag(np.arange(1,2000,2))
In [823]: timeit idx = [next((i for i,x in enumerate(row) if x),None) for row in arr]
10 loops, best of 3: 87.6 ms per loop
In [824]: timeit [row.nonzero()[0][0] for row in arr]
100 loops, best of 3: 6.44 ms per loop

对于相同大小的数组,所有 1 都在行的开头,next 方法要快一些。

In [825]: arr = np.zeros_like(arr,int)
In [826]: arr[:,10]=1
In [827]: timeit idx = [next((i for i,x in enumerate(row) if x),None) for row in arr]
100 loops, best of 3: 3.61 ms per loop
In [828]: timeit [row.nonzero()[0][0] for row in arr]
100 loops, best of 3: 6.41 ms per loop

在 Python 中的短路循环与 C 代码中的完整循环之间存在权衡。


argmax 是另一种在每行中查找第一个非零索引的方法:

idx = np.argmax(arr>0, axis=1)

使用轴参数argmax 必须逐行迭代,然后在行内迭代,但它在编译代码中这样做。使用这样的布尔参数,argmax 会短路。我在另一个关于argmax(或最小值)和nan 值的问题中对此进行了探讨,这也是短路的。

https://***.com/a/41324751/901925


另一种可能性(通灵@Divakar?)

def foo(arr):
    I,J=np.where(arr>0)
    u,i=np.unique(I,return_index=True)
    return J[i]

【讨论】:

我看到人们对他们的支持发表评论,为什么我不允许?不管怎样,这个是给argmax-short-circuiting-booleans nugget 的!【参考方案2】:

您不需要“将 numpy 数组转换为列表”,您需要一种更好的方法来查找非零元素。为此,您应该使用nonzero:

返回非零元素的索引。

还有这样的:

import numpy as np

arr = np.array([0, 0, 9, 2])
print(arr[arr.nonzero()][0])
# 9

或者:

import numpy as np

matrix = np.array([[0, 0, 9, 2], [0, 3, 0, 1]])

for row in matrix:
    print(row[row.nonzero()][0])
# 9
# 3

【讨论】:

对于不太稀疏的大行,这不是最快的。 OP 的生成器构造的重点不是搜索整行,而是在找到第一个非零元素后立即停止。假设固定比例的非零元素,您的解决方案是行长 n 中的 O(n),OP 是 O(1) 平均情况。 是的,但是 Python 循环比编译的 nonzero 慢几个数量级。如果第一个非零值接近行的开头,则短路循环可能会更快,但如果它下降很长,它会变慢。在比较迭代 v 编译操作时,O(n) v O(1) 几乎没有意义。 @hpaulj 是的,这取决于实际数字,但拥有大型非稀疏矩阵的情况并不罕见。立即放弃生成器技巧,对我来说似乎不是一个好建议。 我对权衡进行了一些测试。我还意识到argmax 可以工作,并且在某些情况下会短路。【参考方案3】:

我的猜测是,和你之前的许多其他人一样,包括我自己,你也被 np.matrix 类绊倒了。

对此类的实例进行切片会产生意想不到的结果:

>> id = np.identity(4)
>>> type(id)
<class 'numpy.ndarray'>
>>> id[2]
array([ 0.,  0.,  1.,  0.])    #  shape == (4,)
>>> id_m = np.matrix(id)
>> type(id_m)
<class 'numpy.matrixlib.defmatrix.matrix'>
>>> id_m[2]
matrix([[ 0.,  0.,  1.,  0.]]) #  shape == (4, 1)

正如您所怀疑的,这可能也是您的生成器技巧不起作用的原因。 遍历np.matrix 的一行会因为它是嵌套的,一次返回整行然后停止。

如果出于某种原因您正在处理一个矩阵,但希望它表现得像一个数组,您可以使用.A 属性。

>>> id_m.A
array([[ 1.,  0.,  0.,  0.],
       [ 0.,  1.,  0.,  0.],
       [ 0.,  0.,  1.,  0.],
       [ 0.,  0.,  0.,  1.]])

最后一句话:

不要将您的行转换为此处的列表!您使用的生成器技巧的要点是尽快停止搜索。想象一下,您的行有 100,000 个元素,并且每个元素都是非零的。生成器将查看前几个,一旦找到第一个非零值(几乎可以肯定在前 50 个之内),它将跳过该行的其余部分(> 99,950)。如果您转换为列表,您将丢弃此保存,因为要生成等效列表,必须读取每个元素。这也是为什么在这种情况下生成器可以与向量化的 numpy 函数竞争的原因。

【讨论】:

以上是关于如何将 Numpy 格式的列表转换为 python的主要内容,如果未能解决你的问题,请参考以下文章

将 NumPy 数组转换为 Python 列表结构?

如何使用 SWIG 将 C++ 数组转换为 Python 列表?

将 2d numpy 数组转换为列表列表 [重复]

Python将numpy数组的列表转换为2d数组

如何在 Python 中从 Numpy 矩阵创建列表

将 NumPy 数组转换为 cufftComplex