是否有人知道如何在矩阵中逐行获取唯一元素。对于例如输入矩阵可能如下:
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
答案 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
相同的顺序返回唯一值;根据问题下方的评论,不需要对值进行排序。
最有效的方法可能取决于数组中的行数。
如果行数不是太大,使用map
或for-loop
分别处理每一行的方法都很好,
但是如果有很多行,你可以通过使用numpy技巧来处理整个数组,只需调用一次np.unique就可以做得更好。
诀窍是为每一行添加一个唯一的虚数。
这样,当你调用np.unique
时,原始数组中的浮点数将是
如果它们出现在不同的行中,则被识别为不同的值,但要进行处理
如果它们出现在同一行中,则为相同的值。
下面,这个技巧在函数using_complex
中实现。以下是将原始方法rowWiseUnique
与using_complex
和solve
进行比较的基准:
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)))