【问题标题】:Apply numpy nonzero row-wise?逐行应用numpy非零?
【发布时间】:2014-07-11 17:45:07
【问题描述】:

我有一个二维布尔数组,我试图从中提取真值的索引。 Numpy 的非零函数将我的二维数组分解为位置的 x 和 y 列表,这是有问题的。

是否可以在保留行顺序的同时找到true 元素的列索引?

列中的每个真实值都在同一行中相互关联,因此将它们分成(行索引,列索引)对没有帮助。这可能吗?

我在想np.apply_along_axis 可能有用。

【问题讨论】:

  • 您希望看到什么输出?数组列表,每行一个?

标签: numpy


【解决方案1】:

我不太明白你想要什么(也许举个例子会有所帮助),但有两个猜测:

如果要查看一行是否有 True,则:

np.any(a, axis=1)

将为您提供一个包含每行布尔值的数组。

或者,如果您想逐行获取Trues 的索引,那么

testarray = np.array([
    [True, False, True],
    [True, True, False],
    [False, False, False],
    [False, True, False]])

collists = [ np.nonzero(t)[0] for t in testarray ]

这给出了:

>>> collists
[array([0, 2]), array([0, 1]), array([], dtype=int64), array([1])]

如果您想知道第 3 行带有 True 的列的索引,那么:

>>> collists[3]
array([1])  

没有纯粹的基于数组的方法来实现这一点,因为每行上的项目数各不相同。这就是我们需要列表的原因。另一方面,性能还不错,我用一个 10000 x 10000 的随机布尔数组试了一下,完成任务花了 774 毫秒。

【讨论】:

  • 我知道列号不同的问题。我很惊讶列表的表现如此之好。我将不得不检查这种方式是否足够快。
【解决方案2】:

您可以使用 pandas 来完成此操作。下面的示例通过使用矢量化操作为您提供每行的非零元素的索引 - 输入数据中的每个列数一个。

import numpy as np
import pandas as pd

np.random.seed(0)

size = int(1e4), 5
d1 = pd.DataFrame(np.random.randint(5, size=size))

print(d1)

nz = pd.Series(np.count_nonzero(d1, axis=1))

max_nz = nz.max()

dfs = []
for _nz, nzdf in d1.groupby(nz, sort=False):

    nz = np.apply_along_axis(lambda r: np.nonzero(r)[0], 1, nzdf)

    mock_result = pd.DataFrame(np.ones(shape=(len(nzdf), max_nz)) - 2, index=nzdf.index)

    for i in range(nz.shape[1]):
        mock_result.iloc[:, i] = nz[:, i]

    dfs.append(mock_result)

result = pd.concat(dfs).sort_index()
print(result)

它会打印出来

      0  1  2  3  4
0     4  0  3  3  3
1     1  3  2  4  0
2     0  4  2  1  0
3     1  1  0  1  4
4     3  0  3  0  2
...  .. .. .. .. ..
9995  0  2  3  1  3
9996  3  3  2  3  1
9997  4  0  3  4  3
9998  4  2  4  0  0
9999  0  3  4  1  2

[10000 rows x 5 columns]
        0    1    2    3    4
0     0.0  2.0  3.0  4.0 -1.0
1     0.0  1.0  2.0  3.0 -1.0
2     1.0  2.0  3.0 -1.0 -1.0
3     0.0  1.0  3.0  4.0 -1.0
4     0.0  2.0  4.0 -1.0 -1.0
...   ...  ...  ...  ...  ...
9995  1.0  2.0  3.0  4.0 -1.0
9996  0.0  1.0  2.0  3.0  4.0
9997  0.0  2.0  3.0  4.0 -1.0
9998  0.0  1.0  2.0 -1.0 -1.0
9999  1.0  2.0  3.0  4.0 -1.0

[10000 rows x 5 columns]

使用这种技术,我能够显着减少基于行的scipy.stats.rankdata 版本的运行时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    • 2013-04-18
    • 2011-12-07
    • 2019-02-27
    • 2013-01-16
    相关资源
    最近更新 更多