我的问题类似于this one,但区别在于我需要一个零和一组数组作为输出。我有一个零的原始时间序列和具有高自相关的那些(即,那些是聚类的)。对于某些重要性测试,我需要创建具有相同数量的零和1的随机数组。即但是,原始数组的排列也应该与原始数组保持相同/相似,因此简单的np.permutation
对我没有帮助。
由于我正在进行多项实现,因此我需要一种尽可能快的解决方案。任何帮助深表感谢。
答案 0 :(得分:2)
根据您提及的问题,您希望x
置换
np.corrcoef(x[0: len(x) - 1], x[1: ])[0][1]
不会改变。
假设序列 x 由
组成z 1 o 1 z 2 o 2 z 3 o 3 ... z k o k ,
其中每个 z i 是一个0的序列,每个 o i 是一个1s的序列。 (有四种情况,取决于序列是以0还是1开头,以及它是以0还是1结束,但它们原则上都是相同的。)
假设 p 和 q 是 {1,...,k} 的每个排列,并考虑序列
z p [1] o q [1] z p [2] o q [2] z p [3] o q [3] ... z p [k] o q [k ] 子> ,
,即0s和1s的每个游程长度子序列已在内部置换。
例如,假设原始序列是
0,0,0,1,1,0,1 。
然后
0,0,0,1,0,1,1 ,
就是这样的排列,以及
0,1,1,0,0,0,1 ,
和
0,1,0,0,0,1,1 。
执行此排列不会改变相关性:
因此,这提供了一种生成不影响相关性的排列的方法。 (另外,在最后看到另一种更简单,更有效的方法,可以在许多常见情况下使用。)
我们从函数preprocess
开始,它接受序列,并返回一个元组starts_with_zero, zeros, ones
,分别表示
x
是否以0 在代码中,这是
import numpy as np
import itertools
def preprocess(x):
def find_runs(x, val):
matches = np.concatenate(([0], np.equal(x, val).view(np.int8), [0]))
absdiff = np.abs(np.diff(matches))
ranges = np.where(absdiff == 1)[0].reshape(-1, 2)
return ranges[:, 1] - ranges[:, 0]
starts_with_zero = x[0] == 0
run_lengths_0 = find_runs(x, 0)
run_lengths_1 = find_runs(x, 1)
zeros = [np.zeros(l) for l in run_lengths_0]
ones = [np.ones(l) for l in run_lengths_1]
return starts_with_zero, zeros, ones
(此功能借鉴this question的答案。)
要使用此功能,您可以执行此操作,例如
x = (np.random.uniform(size=10000) > 0.2).astype(int)
starts_with_zero, zeros, ones = preprocess(x)
现在我们编写一个函数来在内部置换0和1运行,并连接结果:
def get_next_permutation(starts_with_zero, zeros, ones):
np.random.shuffle(zeros)
np.random.shuffle(ones)
if starts_with_zero:
all_ = itertools.izip_longest(zeros, ones, fillvalue=np.array([]))
else:
all_ = itertools.izip_longest(ones, zeros, fillvalue=np.array([]))
all_ = [e for p in all_ for e in p]
x_tag = np.concatenate(all_)
return x_tag
要生成另一个排列(具有相同的相关性),您可以使用
x_tag = get_next_permutation(starts_with_zero, zeros, ones)
要生成许多排列,您可以这样做:
starts_with_zero, zeros, ones = preprocess(x)
for i in range(<number of permutations needed):
x_tag = get_next_permutation(starts_with_zero, zeros, ones)
示例强>
假设我们运行
x = (np.random.uniform(size=10000) > 0.2).astype(int)
print np.corrcoef(x[0: len(x) - 1], x[1: ])[0][1]
starts_with_zero, zeros, ones = preprocess(x)
for i in range(10):
x_tag = get_next_permutation(starts_with_zero, zeros, ones)
print x_tag[: 50]
print np.corrcoef(x_tag[0: len(x_tag) - 1], x_tag[1: ])[0][1]
然后我们得到:
0.00674330566615
[ 1. 1. 1. 1. 1. 0. 0. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 0.
1. 1. 0. 1. 1. 1. 1. 0. 1. 1. 0. 0. 1. 0. 1. 1. 1. 1.
0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
0.00674330566615
[ 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
1. 1. 1. 1. 0. 1. 1. 0. 1. 1. 1. 1. 1. 1. 0. 0. 1. 0.
1. 1. 1. 1. 0. 0. 0. 1. 1. 1. 1. 1. 1. 1.]
0.00674330566615
[ 1. 1. 1. 1. 1. 0. 0. 1. 1. 1. 0. 0. 0. 0. 1. 0. 1. 1.
1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 0. 1. 1.
1. 1. 1. 1. 1. 1. 0. 1. 0. 0. 1. 1. 1. 0.]
0.00674330566615
[ 1. 1. 1. 1. 0. 1. 0. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 0.
1. 1. 1. 1. 1. 0. 0. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1.
1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 0. 0. 1.]
0.00674330566615
[ 1. 1. 1. 1. 0. 0. 0. 0. 1. 1. 0. 1. 1. 0. 0. 1. 0. 1.
1. 1. 0. 1. 0. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 0. 0. 1.
0. 1. 1. 1. 1. 1. 1. 0. 1. 0. 1. 1. 1. 1.]
0.00674330566615
[ 1. 1. 0. 1. 1. 1. 0. 0. 1. 1. 0. 1. 1. 0. 0. 1. 1. 0.
1. 1. 1. 0. 1. 1. 1. 1. 0. 0. 0. 1. 1. 1. 1. 1. 1. 1.
0. 1. 1. 1. 1. 0. 1. 1. 0. 1. 0. 0. 1. 1.]
0.00674330566615
[ 1. 1. 0. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.
1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 0. 1. 1. 1. 1. 1.
1. 1. 0. 1. 0. 1. 1. 0. 1. 0. 1. 1. 1. 1.]
0.00674330566615
[ 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 0. 1. 1. 0. 1. 0. 1. 1.
1. 1. 1. 0. 1. 0. 1. 1. 0. 1. 1. 1. 0. 1. 1. 1. 1. 0.
0. 1. 1. 1. 0. 1. 1. 0. 1. 1. 0. 1. 1. 1.]
0.00674330566615
[ 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0.
1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 0. 1. 1. 1.
0. 1. 1. 1. 1. 1. 1. 0. 1. 1. 0. 1. 1. 1.]
0.00674330566615
[ 1. 1. 0. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 0. 1. 0. 1.
1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1.
1. 1. 0. 1. 0. 1. 0. 1. 1. 1. 1. 1. 1. 0.]
请注意,如果
,则有一个更简单的解决方案您的序列长度 n ,
某些数字 m m&lt;&lt; n 和
m!远远大于您需要的排列数量。
在这种情况下,只需将序列划分为 m (近似)相等的部分,并随机置换它们。如前所述,只有 m - 1 边界以可能影响相关性的方式发生变化。由于 m&lt;&lt; n ,这可以忽略不计。
对于某些数字,假设您有一个包含10000个元素的序列。众所周知,20! = 2432902008176640000可能是你需要的排列远远多于你需要的排列。通过将您的序列分成20个部分并进行排列,您最多可以影响19/10000,并且可能足够小。对于这些尺寸,这是我使用的方法。