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

gfttwv5a  于 2023-06-23  发布在  Python
关注(0)|答案(3)|浏览(102)

我有一个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]]

即使在将行转换为列表之后,也会发生这种情况
有没有什么方法可以将每一行转换为一个列表,这样我就可以找到第一个非零值的索引,或者有没有其他更简单的方法来做到这一点?

sigwle7e

sigwle7e1#

您的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,例如在

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(或min)和nan值的问题中探讨了这一点,这也是短路。
https://stackoverflow.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]
wooyq4lh

wooyq4lh2#

你不需要“将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
af7jpaap

af7jpaap3#

我的猜测是,像你之前的许多人一样,包括我自己,你被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)。如果你转换成list,你就把这种节省扔掉了,因为要生成等价的list,每个元素都必须被读取。这也是为什么在这种情况下生成器可以与向量化的numpy函数竞争的原因。

相关问题