问题描述
例如,假设我有一个(n,2)
维度张量t
,其元素全部来自包含随机整数的集合S
。我想构建另一个张量d
,其大小为(m,2)
,其中每个元组中的各个元素都来自S
,但整个元组不会出现在t
中。
例如
S = [0,1,2,3,7]
t = [[0,1],[7,3],[3,1]]
d = some_algorithm(S,t)
/*
d =[[2,2],4]]
*/
在python中最有效的方法是什么?最好使用pytorch或numpy,但我可以解决一般的解决方案。
在我幼稚的尝试中,我只是使用
d = np.random.choice(S,(m,2))
non_dupes = [i not in t for i in d]
d = d[non_dupes]
但是t和S都非常大,并且要花费大量时间(更不用说,很少会生成(m,2)
数组)。我觉得我必须要做一些花哨的张量操作才能实现这一目标,或者对t
中的值进行大型哈希映射,因此检查t
中的成员身份为O(1)
,但这只会在内存上产生相同的问题。有没有更有效的方法?
大概的解决方案也是可以的。
解决方法
我幼稚的尝试是将问题简化为整数集问题的基本转换功能:
定义和假设:
- 让S成为集合(唯一元素)
- 让L为S中的元素数
- 让它成为带有S元素的M元组的集合
- t中元素的原始顺序不相关
- 让I(x)成为S中元素x的索引函数
- 让x [n]成为t元素的第n个元组成员
- 让f(x)是我们的基本变换函数(f ^ -1是其逆函数)
由于S是一个集合,我们可以使用S中的元素作为数字将t中的每个元素作为M位数字写入基数L。
对于M = 2,转换看起来像 f(x)= I(x [1])* L ^ 1 + I(x [0])* L ^ 0
f ^ -1(x)也是不重要的... x mod L以获取最低有效数字的索引。 floor(x / L)并重复直到提取所有索引。在S中查找值并构造元组。
因为现在您可以将t重新设置为一个整数集(读取hastable),计算逆集合d变得微不足道
从L ^(M-1)循环到(L ^(M + 1)-1),并询问您的哈希表元素是否在t或d中
如果S的大小太大,您也可以针对哈希表的t倒数的子集绘制随机数
这对您有帮助吗?
,如果|t| + |d| << |S|^2
,则在一次迭代中再次选择某个随机元组的概率相对较小。
更确切地说,如果(|t|+|d|) / |S|^2 = C
代表某个常数C<1
,则如果您重绘一个元素直到它成为“新”元素,则所需的重绘次数为1/(1-C)
这意味着,通过执行此操作并重新绘制元素直到这是一个新元素,您获得O((1/(1-C)) * |d|)
次来处理一个新元素(平均),如果{{1 }}确实是恒定的。
可以通过以下几种方式来检查元素是否已经“可见”:
- 保留
O(|d|)
和C
的哈希集。这需要额外的空间,但是每次查找都是t
时间不变。您也可以使用bloom filter而不是存储已经看到的实际元素,这会产生一些错误,表示虽然已经“看到”了一个元素,但实际上却不是,但是别无选择-所以您仍然将d
中的所有元素都设为唯一。 - 就地排序
O(1)
,并使用二进制搜索。这样会添加d
预处理,并为每次查找添加t
,但不需要额外的空间(除了存储O(|t|log|t|)
的空间)。
如果实际上O(log|t|)
非常接近d
,那么|d| + |t|
的时间解决方案可能是在可用选项上使用Fisher Yates shuffle ,然后选择第一个{未出现在|S|^2
中的{1}}个元素。