繁体   English   中英

有没有办法对 NumPy 数组中具有相同值的所有行应用 function?

[英]Is there a way to apply a function over all rows with the same values in a NumPy array?

假设我们有一个矩阵 A,它具有以下值:

In [2]: A
Out[2]: 
array([[1, 1, 3],
       [1, 1, 5],
       [1, 1, 7],
       [1, 2, 3],
       [1, 2, 9],
       [2, 1, 5],
       [2, 2, 1],
       [2, 2, 8],
       [2, 2, 3]])

有没有一种方法可以应用 function,例如np.mean ,对第一列和第二列相等的第三列的值按行应用,即获得矩阵 B:

In [4]: B
Out[4]: 
array([[1, 1, 5],
       [1, 2, 6],
       [2, 1, 5],
       [2, 2, 4]])

我的实际用例要复杂得多。 我有一个大约 1M 行和 4 列的大矩阵。 前三列对应于点云中点的 (x, y, z) 坐标,第四列是某个值 function f,其中 f = f(x, y, z)。 我必须对所有相等的 (y, z) 对沿 x 轴(矩阵的第一列)执行积分。 我最终必须得到一个矩阵,其中有一些行数对应于唯一 (y, z) 对的数量和三列:y 轴、z 轴和从积分中获得的值。 我有一些想法,但所有这些想法都包括多个 for 循环和潜在的 memory 问题。

有没有办法以矢量化方式执行此操作?

一个可能的解决方案:

import numpy as np

A = np.array([[1, 1, 3],
       [1, 1, 5],
       [1, 1, 7],
       [1, 2, 3],
       [1, 2, 9],
       [2, 1, 5],
       [2, 2, 1],
       [2, 2, 8],
       [2, 2, 3]]) 

uniquePairs = np.unique(A[:,:2], axis=0)
output = np.empty((uniquePairs.shape[0], A.shape[1]))
for iPair, pair in enumerate(uniquePairs):
    output[iPair,:2] = pair
    output[iPair,2] = np.mean( A[np.logical_and(A[:,0]==pair[0], A[:,1]==pair[1]),2] )
    
print(output)

output 是

[[1. 1. 5.]
 [1. 2. 6.]
 [2. 1. 5.]
 [2. 2. 4.]]

还有一个更紧凑的变体,但可能可读性较差:

uniquePairs = np.unique(A[:,:2], axis=0)
output = np.array([[*pair,  np.mean(A[np.logical_and(A[:,0]==pair[0], A[:,1]==pair[1]),2])] for iPair, pair in enumerate(uniquePairs)])

你可以使用pandas ,如果你有很多数据:

import pandas as pd
df = pd.DataFrame(A, columns = ['id1','id2' ,'value'])
B = df.groupby(['id1','id2'])['value'].mean().reset_index().to_numpy()

output:

>>
[[1. 1. 5.]
 [1. 2. 6.]
 [2. 1. 5.]
 [2. 2. 4.]]

我认为这是最快的方法

import numpy as np

A = np.array(
    [
        [1, 1, 3],
        [1, 1, 5],
        [1, 1, 7],
        [1, 2, 3],
        [1, 2, 9],
        [2, 1, 5],
        [2, 2, 1],
        [2, 2, 8],
        [2, 2, 3],
    ]
)

result = np.mean(A[:, 2], where=A[:, 0] == A[:, 1])

这可能就是您要找的。 您可以使用A[:, n]访问列。

numpy没有内置grouping工具。 由于各组的长度不同,因此它们需要单独的mean调用。 因此需要一定程度的迭代。

defaultdict是一种对值进行分组的简便方法

In [64]: from collections import defaultdict
In [65]: dd = defaultdict(list)
In [66]: for row in A:
    ...:     dd[tuple(row[:2])].append(row[-1])
In [67]: dd
Out[67]: 
defaultdict(list,
            {(1, 1): [3, 5, 7],
             (1, 2): [3, 9],
             (2, 1): [5],
             (2, 2): [1, 8, 3]})
In [68]: {k: np.mean(v) for k, v in dd.items()}
Out[68]: {(1, 1): 5.0, (1, 2): 6.0, (2, 1): 5.0, (2, 2): 4.0}

我们可以创建一个方法数组:

In [72]: np.array([k + (np.mean(v),) for k, v in dd.items()])
Out[72]: 
array([[1., 1., 5.],
       [1., 2., 6.],
       [2., 1., 5.],
       [2., 2., 4.]])

一些比较时间 - 通常需要注意缩放到更大的 arrays。

In [99]: %%timeit
    ...: dd = defaultdict(list)
    ...: for row in A:
    ...:     dd[tuple(row[:2])].append(row[-1])
    ...: np.array([k + (np.mean(v),) for k, v in dd.items()])
132 µs ± 92.9 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [97]: %%timeit
    ...: df = pd.DataFrame(A, columns=["id1", "id2", "value"])
    ...: B = df.groupby(["id1", "id2"])["value"].mean().reset_index().to_numpy()
2.27 ms ± 123 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [102]: %%timeit
     ...: uniquePairs = np.unique(A[:, :2], axis=0)
     ...: output = np.ndarray((uniquePairs.shape[0], A.shape[1]))
     ...: for iPair, pair in enumerate(uniquePairs):
     ...:     output[iPair, :2] = pair
     ...:     output[iPair, 2] = np.mean(
     ...:         A[np.logical_and(A[:, 0] == pair[0], A[:, 1] == pair[1]), 2]
     ...:     )
279 µs ± 216 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

另一个需要更多工作才能完全发挥作用的想法是:

In [106]: %%timeit
     ...: out = np.zeros((2, 2))
     ...: np.add.at(out, (A[:, 0] - 1, A[:, 1] - 1), A[:, -1])
     ...: cnt = np.zeros((2, 2))
     ...: np.add.at(cnt, (A[:, 0] - 1, A[:, 1] - 1), 1)
     ...: res = out / cnt
38.9 µs ± 62.5 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM