我试图使用numpy / pandas构建滑动窗口样式比较器。我有列表列表,每个列表的长度不同。我想将每个列表与另一个列表进行比较,如下所示:
lists = [[10,15,5],[5,10],[5]]
window_diff(l[1],l[0]) = 25
列表[0]和列表[1]的窗口差异将使用下图中显示的以下窗口滑动技术给出25。因为列表[1]是较短的路径,所以我们将其向右移动一次,从而产生2个比较窗口。如果您对下图中的最后一行求和,我们会使用两个比较窗口获得两个列表之间的总差异;在这种情况下共计25个。要注意我们正在采用绝对差异。
该函数应聚合每个列表与其他列表之间的总window_diff,因此在这种情况下
tot = total_diffs(lists)
tot>>[40, 30, 20]
# where tot[0] represents the sum of lists[0] window_diff with all other lists.
我想知道在熊猫或numpy中是否有快速通道。目前我正在使用一个非常漫长的循环过程来循环遍历每个列表,然后通过按照较长列表移动较短列表来逐位比较。
我的方法适用于短列表,但我的数据集长度为10,000个列表,其中一些列表包含60个左右的数据点,因此速度是此处的标准。我想知道numpy,熊猫是否对此有一些建议?感谢
from random import randint
lists = [[random.randint(0,1000) for r in range(random.randint(0,60))] for x in range(100000)]
答案 0 :(得分:2)
步骤:
在列表输入列表的每对列表中,为较大的数组创建滑动窗口,然后获得该对中较小的一个的绝对差异。我们可以使用NumPy strides
来获取那些滑动窗口。
获得总和并将此总和存储为成对差异化。
最后在上一步的2D
数组的每一行和col上求和,它们的总和是最终输出。
因此,实现看起来像这样 -
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()
strided_app
的灵感来自here
。
示例输入,输出 -
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])
答案 1 :(得分:2)
仅仅为了完美了解@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可能会加速一些事情。