当前位置: 代码迷 >> python >> 如何将Numpy格式的列表转换为python
  详细解决方案

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

热度:65   发布时间:2023-06-13 15:12:53.0

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

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

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

总是返回0的val

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

rowList = row.tolist()

但这也返回了相同的值

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

即。

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

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

有什么方法可以将每一行都转换为列表,以便随后找到第一个非零值的索引,或者还有另一种方法可以更简单地做到这一点?

您的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 (或min)和nan值的问题中对此进行了探讨,它们也会短路。


另一种可能性(引导@Divakar吗?)

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

您不需要“将一个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

我的猜测是,像包括您自己在内的许多其他人一样,您被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函数竞争的原因。