繁体   English   中英

用numpy数组和元组保持每个元素一次发生的快速方法

[英]Fast way to keep one occurancy per element with numpy array and tuple

关于堆栈的第一个问题,大家好!

我有一个元组,带有两个一维np矩阵,例如np.nonzero:

(array([479, 479, 479, 480, 480, 480, 481, 481, 481, 482, 482, 482, 650, 650, 650, 651, 651, 651, 652, 652, 652, 653, 653, 653, 654, 654, 654, 708, 708, 708, 709, 709, 709, 710, 710, 710, 711, 711, 711, 712, 712, 712, 713, 713, 713], dtype=int64), array([ 859, 860, 861, 859, 860, 861, 859, 860, 861, 859, 860, 861, 1045, 1046, 1047, 1045, 1046, 1047, 1045, 1046, 1047, 1045, 1046, 1047, 1045, 1046, 1047, 1039, 1040, 1041, 1039, 1040, 1041, 1039, 1040, 1041, 1039, 1040, 1041, 1039, 1040, 1041, 1039, 1040, 1041], dtype=int64))

但是在我将来的使用中,该元组将更大。 我正在寻找最快的方法来在元组的第一列中仅保留每个元素(第一元素)的一次出现,并在第二列中保持其第二坐标。 另外,第一列已排序

对于我的示例,我想要以下输出:

(array([479, 480, 481, 482, 650, 651, 652, 653, 654, 708, 709, 710, 711, 712], dtype=int64), array([861, 861, 861, 861, 1047, 1047, 1047, 1047, 1047, 1041, 1041, 1041, 1041, 1041],dtype=int64))

一个幼稚的解决方案可能是:

for k in range(len(nozero[0])-1):
    i = nozero[0][k]
    i2 = nozero[0][k+1]
    j = nozero[1][k]
    j2 = nozero[1][k+1]

if  i != i2:
    x.append(i)
    y.append(j)

随时向我提出任何建议,也可以建议您整理数据! (或者如果您想要更好的解释)。

非常感谢 !

您可以在第一个数组上使用np.diff来查找所有第一次出现的掩码。 然后,只需使用遮罩将每个数组切片即可。

请注意, np.diff结果是数组的大小比原始数组小一个,因此我们在前面加上1 (数组中的第一个元素始终是同类中的第一个)。

from numpy import array,int64
import numpy as np
arr1, arr2 = (array([479, 479, 479, 480, 480, 480, 481, 481, 481, 482, 482, 482, 650,
       650, 650, 651, 651, 651, 652, 652, 652, 653, 653, 653, 654, 654,
       654, 708, 708, 708, 709, 709, 709, 710, 710, 710, 711, 711, 711,
       712, 712, 712, 713, 713, 713], dtype=int64),
array([ 859,  860,  861,  859,  860,  861,  859,  860,  861,  859,  860,
        861, 1045, 1046, 1047, 1045, 1046, 1047, 1045, 1046, 1047, 1045,
       1046, 1047, 1045, 1046, 1047, 1039, 1040, 1041, 1039, 1040, 1041,
       1039, 1040, 1041, 1039, 1040, 1041, 1039, 1040, 1041, 1039, 1040,
       1041], dtype=int64))

first_occurences_mask = np.concatenate([[1], np.diff(arr1)], axis=0) > 0
first_occurences_mask
=> 
array([ True, False, False,  True, False, False,  True, False, False,
        True, False, False,  True, False, False,  True, False, False,
        True, False, False,  True, False, False,  True, False, False,
        True, False, False,  True, False, False,  True, False, False,
        True, False, False,  True, False, False,  True, False, False], dtype=bool)

res1, res2 = (arr1[first_occurences_mask], arr2[first_occurences_mask])
res1, res2
=> 
(array([479, 480, 481, 482, 650, 651, 652, 653, 654, 708, 709, 710, 711,
       712, 713]),
 array([ 859,  859,  859,  859, 1045, 1045, 1045, 1045, 1045, 1039, 1039,
       1039, 1039, 1039, 1039]))

(顺便说一句,这是一个很好的第一个问题。在发布之前,您已经阅读了规则和最佳实践,并显示出来。)

编辑(@alejandro)-时间比较

为了证明此方法比@BM更快,下面我对两者进行了比较:

from numpy import array,int64
import numpy as np
import time

time1 = []
time2 = []

nelements = np.logspace(1,7)

for i in nelements:
    arr = np.random.randint(0,i, i)

    start = time.time()
    first_occurences_mask = np.concatenate([[1], np.diff(arr)], axis=0) > 0
    stop = time.time()
    time1.append(stop-start)

    start = time.time()
    np.unique(arr,return_index=True)
    stop = time.time()
    time2.append(stop-start)

得到以下结果:

在此处输入图片说明

该图清楚地表明,对于大数组,使用连接的速度非常快

使用np.unique

In [1]: i,j = nozeros  # your two arrays.
In [3]: uniq,index,count=np.unique(i,return_index=True,return_counts=True)

og i的独特元素在uniq

In [4]: uniq
Out[4]: 
array([479, 480, 481, 482, 650, 651, 652, 653, 654, 708, 709, 710, 711,
       712, 713], dtype=int64)

如果您想要j的最后一个对应元素,例如您的示例:

In [5]: j[index+count-1]
Out[5]: 
array([ 861,  861,  861,  861, 1047, 1047, 1047, 1047, 1047, 1041, 1041,
       1041, 1041, 1041, 1041], dtype=int64)

暂无
暂无

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

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