Python 具有容差的两个数据集的最长公共子序列
我有四个1DPython 具有容差的两个数据集的最长公共子序列,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
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]]