将重复元素设置为零

时间:2015-06-28 06:46:19

标签: python numpy

如何转换数组中的重复元素'数据'变成0?它必须按行进行。

data = np.array([[1,8,3,3,4],
                 [1,8,9,9,4]])

答案应如下:

ans = array([[1,8,3,0,4],
             [1,8,9,0,4]])

4 个答案:

答案 0 :(得分:3)

方法#1

使用np.unique -

的一种方法
# Find out the unique elements and their starting positions
unq_data, idx = np.unique(data,return_index=True)

# Find out the positions for each unique element, their duplicate positions
dup_idx = np.setdiff1d(np.arange(data.size),idx)

# Set those duplicate positioned elemnents to 0s
data[dup_idx] = 0

示例运行 -

In [46]: data
Out[46]: array([1, 8, 3, 3, 4, 1, 3, 3, 9, 4])

In [47]: unq_data, idx = np.unique(data,return_index=True)
    ...: dup_idx = np.setdiff1d(np.arange(data.size),idx)
    ...: data[dup_idx] = 0
    ...: 

In [48]: data
Out[48]: array([1, 8, 3, 0, 4, 0, 0, 0, 9, 0])

方法#2

您还可以使用sortingdifferentiation作为更快的方法 -

# Get indices  for sorted data
sort_idx = np.argsort(data)

# Get duplicate indices and set those in data to 0s
dup_idx = sort_idx[1::][np.diff(np.sort(data))==0]
data[dup_idx] = 0

运行时测试 -

In [110]: data = np.random.randint(0,100,(10000))
     ...: data1 = data.copy()
     ...: data2 = data.copy()
     ...: 

In [111]: def func1(data):
     ...:     unq_data, idx = np.unique(data,return_index=True)
     ...:     dup_idx = np.setdiff1d(np.arange(data.size),idx)
     ...:     data[dup_idx] = 0
     ...: 
     ...: def func2(data):
     ...:     sort_idx = np.argsort(data)
     ...:     dup_idx = sort_idx[1::][np.diff(np.sort(data))==0]
     ...:     data[dup_idx] = 0
     ...:     

In [112]: %timeit func1(data1)
1000 loops, best of 3: 1.36 ms per loop

In [113]: %timeit func2(data2)
1000 loops, best of 3: 467 µs per loop

扩展到2D案例:

方法#2可以扩展为适用于2D数组的情况,避免任何类似的循环 -

# Get indices  for sorted data
sort_idx = np.argsort(data,axis=1)

# Get sorted linear indices
row_offset = data.shape[1]*np.arange(data.shape[0])[:,None]
sort_lin_idx = sort_idx[:,1::] + row_offset

# Get duplicate linear indices and set those in data as 0s
dup_lin_idx = sort_lin_idx[np.diff(np.sort(data,axis=1),axis=1)==0]
data.ravel()[dup_lin_idx] = 0

示例运行 -

In [6]: data
Out[6]: 
array([[1, 8, 3, 3, 4, 0, 3, 3],
       [1, 8, 9, 9, 4, 8, 7, 9],
       [1, 8, 9, 9, 4, 8, 7, 3]])

In [7]: sort_idx = np.argsort(data,axis=1)
   ...: row_offset = data.shape[1]*np.arange(data.shape[0])[:,None]
   ...: sort_lin_idx = sort_idx[:,1::] + row_offset
   ...: dup_lin_idx = sort_lin_idx[np.diff(np.sort(data,axis=1),axis=1)==0]
   ...: data.ravel()[dup_lin_idx] = 0
   ...: 

In [8]: data
Out[8]: 
array([[1, 8, 3, 0, 4, 0, 0, 0],
       [1, 8, 9, 0, 4, 0, 7, 0],
       [1, 8, 9, 0, 4, 0, 7, 3]])

答案 1 :(得分:1)

这是一种简单的纯Python方式:

seen = set()
for i, x in enumerate(data):
    if x in seen:
        data[i] = 0
    else:
        seen.add(x)

答案 2 :(得分:0)

您可以使用嵌套for循环,将数组的每个元素与每个其他元素进行比较,以检查重复记录。语法可能有点偏,因为我对numpy并不熟悉。

for x in range(0, len(data))
   for y in range(x+1, len(data))
      if(data[x] == data[y])
         data[x] = 0

答案 3 :(得分:0)

@Divakar几乎是正确的,但有一些事情可以进一步优化,但不适合评论。开始:

rows, cols = data.shape

第一个操作是对数组进行排序以识别重复项。由于我们要撤消排序,我们需要使用np.argsort,但是如果要确保它是保留的每个重复值的第一次出现,则需要使用稳定的排序算法:< / p>

sort_idx = data.argsort(axis=1, kind='mergesort')

一旦我们有索引来排序data,要获得数组的排序副本,使用索引比重新排序数组更快:

sorted_data = data[np.arange(rows)[:, None], sort_idx]

虽然原理类似于使用np.diff的原则,但使用布尔运算通常更快。我们想要一个满是False的数组,其中每个值的第一次出现,以及重复项的True

sorted_mask = np.concatenate((np.zeros((rows, 1), dtype=bool),
                              sorted_data[:, :-1] == sorted_data[:, 1:]),
                             axis=1)

我们现在使用该掩码将所有重复项设置为零:

sorted_data[sorted_mask] = 0

我们最终撤消了排序。要恢复排列,您可以对定义它的索引进行排序,即您可以执行以下操作:

invert_idx = sort_idx.argsort(axis=1, kind='mergesort')
ans = sorted_data[np.arange(rows)[:, None], invert_idx]

但使用赋值更有效,即:

ans = np.empty_like(data)
ans[np.arange(rows), sort_idx] = sorted_data

全部放在一起:

def zero_dups(data):
    rows, cols = data.shape
    sort_idx = data.argsort(axis=1, kind='mergesort')
    sorted_data = data[np.arange(rows)[:, None], sort_idx]
    sorted_mask = np.concatenate((np.zeros((rows, 1), dtype=bool),
                                  sorted_data[:, :-1] == sorted_data[:, 1:]),
                                 axis=1)
    sorted_data[sorted_mask] = 0
    ans = np.empty_like(data)
    ans[np.arange(rows)[:, None], sort_idx] = sorted_data

    return ans