Numpy:Row Wise独特的元素

时间:2014-11-16 14:51:17

标签: python numpy scipy

是否有人知道如何在矩阵中逐行获取唯一元素。对于例如输入矩阵可能如下:

a = [[1,2,1,3,4,1,3],
     [5,5,3,1,5,1,2],
     [1,2,3,4,5,6,7],
     [9,3,8,2,9,8,4],
     [4,6,7,4,2,3,5]]

它应该返回以下内容:

b = rowWiseUnique(a)
=>  b = [[1,2,3,4,0,0,0],
       [5,3,1,2,0,0,0],
       [1,2,3,4,5,6,7],
       [9,3,8,2,4,0,0],
       [4,6,7,2,3,5,0]]

在numpy中执行此操作的最有效方法是什么?我尝试了下面的代码,有没有更好更短的方法呢?

import numpy as np
def uniqueRowElements(row):
    length = row.shape[0]
    newRow = np.unique(row)
    zerosNumb = length-newRow.shape[0]
    zeros = np.zeros(zerosNumb)
    nR = np.concatenate((newRow,zeros),axis=0)
    return nR    

b = map(uniqueRowElements,a)
b = np.asarray(b)
print b

5 个答案:

答案 0 :(得分:3)

假设a中的值是浮点数,您可以使用:

def using_complex(a):
    weight = 1j*np.linspace(0, a.shape[1], a.shape[0], endpoint=False)
    b = a + weight[:, np.newaxis]
    u, ind = np.unique(b, return_index=True)
    b = np.zeros_like(a)
    np.put(b, ind, a.flat[ind])
    return b

In [46]: using_complex(a)
Out[46]: 
array([[1, 2, 0, 3, 4, 0, 0],
       [5, 0, 3, 1, 0, 0, 2],
       [1, 2, 3, 4, 5, 6, 7],
       [9, 3, 8, 2, 0, 0, 4],
       [4, 6, 7, 0, 2, 3, 5]])

请注意,using_complex不会以与rowWiseUnique相同的顺序返回唯一值;根据问题下方的评论,不需要对值进行排序。


最有效的方法可能取决于数组中的行数。 如果行数不是太大,使用mapfor-loop分别处理每一行的方法都很好, 但是如果有很多行,你可以通过使用numpy技巧来处理整个数组,只需调用一次np.unique就可以做得更好。

诀窍是为每一行添加一个唯一的虚数。 这样,当你调用np.unique时,原始数组中的浮点数将是 如果它们出现在不同的行中,则被识别为不同的值,但要进行处理 如果它们出现在同一行中,则为相同的值。

下面,这个技巧在函数using_complex中实现。以下是将原始方法rowWiseUniqueusing_complexsolve进行比较的基准:

In [87]: arr = np.random.randint(10, size=(100000, 10))

In [88]: %timeit rowWiseUnique(arr)
1 loops, best of 3: 1.34 s per loop

In [89]: %timeit solve(arr)
1 loops, best of 3: 1.78 s per loop

In [90]: %timeit using_complex(arr)
1 loops, best of 3: 206 ms per loop

import numpy as np

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

def using_complex(a):
    weight = 1j*np.linspace(0, a.shape[1], a.shape[0], endpoint=False)
    b = a + weight[:, np.newaxis]
    u, ind = np.unique(b, return_index=True)
    b = np.zeros_like(a)
    np.put(b, ind, a.flat[ind])
    return b

def rowWiseUnique(a):
    b = map(uniqueRowElements,a)
    b = np.asarray(b)
    return b

def uniqueRowElements(row):
    length = row.shape[0]
    newRow = np.unique(row)
    zerosNumb = length-newRow.shape[0]
    zeros = np.zeros(zerosNumb)
    nR = np.concatenate((newRow,zeros),axis=0)
    return nR    

def solve(arr):
    n = arr.shape[1]
    new_arr = np.empty(arr.shape)
    for i, row in enumerate(arr):
        new_row = np.unique(row)
        new_arr[i] = np.hstack((new_row, np.zeros(n - len(new_row))))
    return new_arr

答案 1 :(得分:1)

您可以这样做:

def solve(arr):
    n = arr.shape[1]
    new_arr = np.empty(arr.shape)
    for i, row in enumerate(arr):
        new_row = np.unique(row)
        new_arr[i] = np.hstack((new_row, np.zeros(n - len(new_row))))
    return new_arr

这比OP的1000 X 1000阵列的当前代码快4倍:

>>> arr = np.arange(1000000).reshape(1000, 1000)
>>> %timeit b = map(uniqueRowElements, arr); b = np.asarray(b)
10 loops, best of 3: 71.2 ms per loop
>>> %timeit solve(arr)
100 loops, best of 3: 16.6 ms per loop

答案 2 :(得分:1)

OP解决方案的变化略有改善,当使用numpy.apply_along_axis大型(1000x1000)阵列时,约为3% - 但仍然比@Ashwini解决方案慢一点。

def foo(row):
    b = np.zeros(row.shape)
    u = np.unique(row)
    b[:u.shape[0]] = u
    return b

b = np.apply_along_axis(foo, 1, a)

使用行a = np.random.random_integers(0, 500, (1000*1000)).reshape(1000,1000)中包含重复项的数组,时间比例似乎更接近。

答案 3 :(得分:0)

效率不高,因为将所有零移动到行的末尾可能效率不高。

import numpy as np

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

row_len = len(a[0])

for r in xrange(len(a)):
    found = set()
    for i in xrange(row_len):
        if a[r][i] not in found:
            found.add(a[r][i])
        else:
            a[r][i] = 0
    a[r].sort()
    a[r] = a[r][::-1]

print(a)

输出:

[[4 3 2 1 0 0 0]
 [5 3 2 1 0 0 0]
 [7 6 5 4 3 2 1]
 [9 8 4 3 2 0 0]
 [7 6 5 4 3 2 0]]

答案 4 :(得分:0)

最快的方法应该是使用sort和diff将所有重复项设置为零:

def row_unique(a):
    unique = np.sort(a)
    duplicates = unique[:,  1:] == unique[:, :-1]
    unique[:, 1:][duplicates] = 0
    return unique

这大约是我计算机上unutbu解决方案的三倍:

In [26]: a = np.random.randint(1, 101, size=100000).reshape(1000, 100)

In [27]: %timeit row_unique(a)
100 loops, best of 3: 3.18 ms per loop

In [28]: %timeit using_complex(a)
100 loops, best of 3: 15.4 ms per loop

In [29]: assert np.all(np.sort(using_complex(a)) == np.sort(row_unique(a)))