Python中列表列表的滑动窗口
我正在尝试使用numpy/pandas构建一个滑动窗口样式的比较器。我有一个列表,每个列表都有不同的长度。我想将每个列表与另一个列表进行比较,如下所示:Python中列表列表的滑动窗口,python,pandas,numpy,Python,Pandas,Numpy,我正在尝试使用numpy/pandas构建一个滑动窗口样式的比较器。我有一个列表,每个列表都有不同的长度。我想将每个列表与另一个列表进行比较,如下所示: lists = [[10,15,5],[5,10],[5]] window_diff(l[1],l[0]) = 25 使用下图所示的窗口滑动技术,列表[0]和列表[]的窗口差异将为25。因为lists[]是较短的路径,所以我们将其向右移动一次,从而产生两个比较窗口。如果对下图中的最后一行求和,我们将使用两个比较窗口得到两个列表之间的总差异;
lists = [[10,15,5],[5,10],[5]]
window_diff(l[1],l[0]) = 25
使用下图所示的窗口滑动技术,列表[0]和列表[]的窗口差异将为25。因为lists[]是较短的路径,所以我们将其向右移动一次,从而产生两个比较窗口。如果对下图中的最后一行求和,我们将使用两个比较窗口得到两个列表之间的总差异;在这种情况下,总共有25个。要注意的是,我们采用了绝对差异
函数应该聚合每个列表和其他列表之间的总窗口差异,因此在本例中
tot = total_diffs(lists)
tot>>[40, 30, 20]
# where tot[0] represents the sum of lists[0] window_diff with all other lists.
我想知道是否有一种快速的方法可以在熊猫或裸体动物身上做到这一点。目前,我正在使用一个非常冗长的过程来循环遍历每个列表,然后通过根据较长的列表移动较短的列表来按位进行比较
我的方法适用于短列表,但我的数据集有10000个列表,其中一些列表包含60个左右的数据点,因此速度是这里的一个标准。我想知道numpy,pandas对此是否有一些建议?谢谢
样本问题数据
步骤:
- 在列表输入列表中的每一对列表中,为较大的数组创建滑动窗口,然后获得与该对中较小数组的绝对差值。我们可以用它来装滑动窗
- 获取总和并将此总和存储为成对微分
- 最后,对上一步中的
数组中的每一行和每一列求和,它们的总和即为最终输出2D
import itertools
def strided_app(a, L, S=1 ): # Window len = L, Stride len/stepsize = S
a = np.asarray(a)
nrows = ((a.size-L)//S)+1
n = a.strides[0]
return np.lib.stride_tricks.as_strided(a, shape=(nrows,L), strides=(S*n,n))
N = len(lists)
pair_diff_sums = np.zeros((N,N),dtype=type(lists[0][0]))
for i, j in itertools.combinations(range(N), 2):
A, B = lists[i], lists[j]
if len(A)>len(B):
pair_diff_sums[i,j] = np.abs(strided_app(A,L=len(B)) - B).sum()
else:
pair_diff_sums[i,j] = np.abs(strided_app(B,L=len(A)) - A).sum()
out = pair_diff_sums.sum(1) + pair_diff_sums.sum(0)
对于非常繁重的数据集,这里有一种方法使用了更高级别的循环-
N = len(lists)
out = np.zeros((N),dtype=type(lists[0][0]))
for k,i in enumerate(lists):
for j in lists:
if len(i)>len(j):
out[k] += np.abs(strided_app(i,L=len(j)) - j).sum()
else:
out[k] += np.abs(strided_app(j,L=len(i)) - i).sum()
stridded_应用程序
的灵感来源于
样本输入、输出-
In [77]: lists
Out[77]: [[10, 15, 5], [5, 10], [5]]
In [78]: pair_diff_sums
Out[78]:
array([[ 0, 25, 15],
[25, 0, 5],
[15, 5, 0]])
In [79]: out
Out[79]: array([40, 30, 20])
仅就@Divakar伟大答案的完整性及其对超大数据集的应用而言:
import itertools
N = len(lists)
out = np.zeros(N, dtype=type(lists[0][0]))
for i, j in itertools.combinations(range(N), 2):
A, B = lists[i], lists[j]
if len(A)>len(B):
diff = np.abs(strided_app(A,L=len(B)) - B).sum()
else:
diff = np.abs(strided_app(B,L=len(A)) - A).sum()
out[i] += diff
out[j] += diff
它不会创建不必要的大型数据集,并且只在上三角数组上迭代时更新单个向量
计算仍然需要一段时间,因为在计算复杂性和大于ram的数据集之间存在折衷。对于大于ram的数据集的解决方案通常依赖于迭代,而python在这方面并不擅长。用python在大型数据集上迭代非常慢
将上面的代码翻译成cython可能会加快速度。问题并没有完全说明,也不是很明显。似乎您需要在窗口之间设置l1(abs)距离,因为这是解释
5-10->5
的唯一方法。但我不清楚您在最后一个窗口中仅使用一个元素时的预期行为。你会重复三次,还是只在开头和结尾加两个零?比较第二行和第三行时会发生什么情况?您是要在第二个窗口上滑动2 x 3次,还是只在第三个窗口上滑动2次?嗨,Imanol,我已经更新了问题,以解决我们正在使用abs差异。您是一个向导:)@Divakar,谢谢!您的代码运行得非常好,但是在处理添加到问题中的示例数据时,我遇到了一些关于triu.index的内存问题。谢谢你的帮助@user3063482@Divakar您可以在itertools.组合(范围(N),2)中将i,j的r,c=np.triu_索引(N)
和for循环替换为。不会将所有索引预先计算到内存中,并惰性地生成它们(它本质上是一个python生成器)。然后,您可以将for循环内的行pair diff\u sums[c,r]=pair diff\u sums[r,c]
移位为pair diff\u sums[j,i]=pair diff\u sums[i,j]
另外,pair diff\u sums
可以用于较大的N
,并且只有diff\u sums=np.0(N)#out
然后更新为diff_sums[i]+=pair_diff;diff_sums[j]+=pair_diff
其中pair_diff
是行i
和j
之间的差异,感谢您的帮助!根据您的建议进行了一些编辑!
import itertools
N = len(lists)
out = np.zeros(N, dtype=type(lists[0][0]))
for i, j in itertools.combinations(range(N), 2):
A, B = lists[i], lists[j]
if len(A)>len(B):
diff = np.abs(strided_app(A,L=len(B)) - B).sum()
else:
diff = np.abs(strided_app(B,L=len(A)) - A).sum()
out[i] += diff
out[j] += diff