Python 具有容差的两个数据集的最长公共子序列

Python 具有容差的两个数据集的最长公共子序列,python,numpy,Python,Numpy,我有四个1Dnp。数组s:x1,y1,x2,y2,其中x1和y2具有相同的长度,同样x2和y2具有相同的长度,因为它们是数据集对应的x和y值len(x1)和len(x2)总是不同的。现在让我们假设len(x1)>len(x2)。这两个数组总是有共同的值,但有一种特殊的方式:值并不完全相同,只是在一个公差范围内(由于数值误差等)。公差为0.01的示例: x1=np.数组([0,1.01,1.09,1.53,-9.001,1.2,-52,1.011]) x2=np.数组([1,1.1,1.2,1.5

我有四个1D
np。数组
s:
x1,y1,x2,y2
,其中
x1
y2
具有相同的长度,同样
x2
y2
具有相同的长度,因为它们是数据集对应的x和y值
len(x1)
len(x2)
总是不同的。现在让我们假设
len(x1)>len(x2)
。这两个数组总是有共同的值,但有一种特殊的方式:值并不完全相同,只是在一个公差范围内(由于数值误差等)。公差为0.01的示例:

x1=np.数组([0,1.01,1.09,1.53,-9.001,1.2,-52,1.011])
x2=np.数组([1,1.1,1.2,1.5,-9,82])
我只想保留公共值(以宽容的方式)。使用较短的数组作为参考,在本例中为
x2
x2
中的第一个值是
1
,在
x1
中有一个对应的值,即
1.01
。下一步:
1.2
x2
中也有相应的值,
1.2
。值
1.5
没有相应的值,因为
1.53
超出公差,所以将其过滤掉,以此类推。。 全部结果应为:

x1=np.数组([1.01,1.09,-9.001,1.2])
x2=np.数组([1,1.1,-9,1.2])
为了更进一步,在以这种方式过滤x值的基础上,我想过滤两个数据集相同索引的y值,换句话说,我想找到两个数据集的最长公共子序列。请注意,这里的排序很重要,因为它和y值有关联(如果我们先对x进行argsort,然后重新索引x和y,这并不重要)

根据答案,我尝试了以下内容:

def longest_common_subseq(x1,x2,y1,y2,tol=0.02):
#首先对它们进行排序,以保持x和y的连接
idx1=np.argsort(x1)
x1,y1=x1[idx1],y1[idx1]
idx2=np.argsort(x2)
x2,y2=x2[idx2],y2[idx2]
#这里我假设len(x2)idx=(np.abs(x1[:,None]-x2)我认为这应该可以做到:

def longest_common_subseq(x1, x2, y1, y2, tol=0.02):
    # sort them first to keep x and y connected
    idx1 = np.argsort(x1)
    x1, y1 = x1[idx1], y1[idx1]
    idx2 = np.argsort(x2)
    x2, y2 = x2[idx2], y2[idx2]
    
    # here I assumed that len(x2) < len(x1)
    difference = np.abs(x1[:,None] - x2) <= tol
    no_multiples = difference.cumsum(axis=0).cumsum(axis=0) == 1
    out_idx1 = no_multiples.any(axis=1)
    out_idx2 = no_multiples.any(axis=0)
    return x1[out_idx1], x2[out_idx2], y1[out_idx1], y2[out_idx2]

一种简单的方法是找到所有元素之间的距离:

dist = np.abs(x1 - x2[:, None])
既然你说通常你不会有多个元素在任何其他元素的公差范围内,你可以这样做

i2, i1 = np.nonzero(dist < tol)
您可以从上述数量中找到最长运行的索引:

k = np.argmax(lengths)
start = inds[2 * k]
stop = inds[2 * k + 1]
longest_x1 = x1[i1[start:stop]]
longest_y1 = y1[i1[start:stop]]
longest_x2 = x2[i2[start:stop]]
longest_y2 = y2[i2[start:stop]]

任务的定义不够好。如果
x1=[1,1.02,1.03]
x2=[1.021,1.017]会发生什么情况
?多个答案在
tol=0.02
范围内,而
x1
中的同一个答案最接近
x2
中的不同元素。这里的正确配对是什么?@Aguy这几乎肯定不会发生,因为
x1
x2
最初是相同的数组,其中一个刚刚通过slicing和某些操作。您提到的正确答案是
x1=[1.02]
x2=[1.021]
。我们使用较短的数组作为参考,遍历其元素,查看所需的
tol
x2
中是否有相应的值,并选择最接近的值。一旦我们选择了一个值,我们需要在以后排除它以避免重复。我知道这听起来很复杂,我同意它的定义不够好,也许我以后会重新表述这个问题。但是,您的解决方案返回的是
tol=0.02
的正确结果,请尝试使用
tol=0.2
:返回的数组有不同的长度。现在,我正试图理解为什么会发生这种情况。它(几乎)起作用。行
i2=np.flatnonzero(dist[i1,np.arange(x2.size)]
引发了
索引器
,但是如果我忽略了该部分,它会返回正确的结果。知道为什么会发生这种情况吗?@PéterLeéh。我翻转了该部分的索引。现在已修复。如果需要在多个相邻元素之间进行选择,则只需使用这三行来代替第一个片段。
dist = np.abs(x1 - x2[:, None])
i2, i1 = np.nonzero(dist < tol)
i1 = np.argmin(dist, axis=1)
i2 = np.flatnonzero(dist[np.arange(x2.size), i1] < tol)
i1 = i1[i2]
mask = (np.diff(i1) == 1) & (np.diff(i2) == 1)
# smear the mask to include both endpoints
mask = np.r_[False, mask] | np.r_[mask, False]
# pad the mask to ensure proper indexing and find the changeover points
locs = np.diff(np.r_[False, mask, False])
inds = np.flatnonzero(locs)
lengths = inds[1::2] - inds[::2]
k = np.argmax(lengths)
start = inds[2 * k]
stop = inds[2 * k + 1]
longest_x1 = x1[i1[start:stop]]
longest_y1 = y1[i1[start:stop]]
longest_x2 = x2[i2[start:stop]]
longest_y2 = y2[i2[start:stop]]