生成没有重复列的位向量数组

时间:2019-10-08 11:59:21

标签: python numpy

我有一个尺寸为[batch_size, input_dim]的数组,只需要用01填充即可。我需要每列中的元素都与其余各列不同。我采用了如下方法:

 train_data = np.zeros(shape=[batch, input_dim])
 num_of_ones = random.sample(range(input_dim + 1), batch)
 for k in range(batch):
     num_of_one = num_of_ones[k]
     for _ in range(num_of_one):
         train_data[k][np.random.randint(0, input_dim)] = 1

尽管这保证了不会重复任何元素(由于每个列具有不同数量的1),但是仍然有许多组合被遗漏了。例如,当num_of_one = 1时,存在input_dim种可能性,依此类推。我认为该方法的另一个缺点是batch_sizeinput_dim必须相同(否则random.sample会引发错误)。我不想列出所有可能的方法,因为这将永远需要完成。

有没有简单的方法可以解决上述问题?

4 个答案:

答案 0 :(得分:1)

您可以选择一组介于0和2 ^ {itertools之间的不同数字(在input_dim中查看),并使用它们的二进制表示形式来获取每个值的0和1序列。由于选择的数字是不同的,因此它们的二进制表示形式也将是不同的。

答案 1 :(得分:1)

观察从07的数字的二进制表示形式:

000
001
010
011
100
101
110
111

每行都不一样!因此,我们要做的就是将每一行都转换为列。例如

arr = [
    [0, 0, 0, 0, 1, 1, 1, 1],
    [0, 0, 1, 1, 0, 0, 1, 1],
    [0, 1, 0, 1, 0, 1, 0, 1],
]

此外,请注意我们已经使用了所有独特的可能性。现在,对于3行,我们无法添加第2**3 + 1列。

通常,如果cols > 2**rows,则我们找不到唯一的表示形式。


您可以执行以下操作:

rows = 3
cols = 8

if 2**rows < cols:
    print('Not possible')

arr = [[None] * cols for _ in range(rows)]

for col_idx in range(cols):
    binary = bin(col_idx)[2:]
    binary = binary.zfill(rows)

    for row_idx in range(rows):
        arr[row_idx][col_idx] = int(binary[row_idx])

for row in arr:
    print(row)

时间复杂度:O(rows * cols)

空间复杂度:O(rows * cols)

答案 2 :(得分:1)

为什么你的不工作

您对此行有疑问:

    for _ in range(num_of_one):
        train_data[k][np.random.randint(0, input_dim)] = 1

由于您选择了要设置为1的随机行,因此可以重复这些行,并且不能保证每列中的行数都正确,因此可以重复。从本质上讲,这并不比将整个数组随机化并希望没有重复项更好。

解决方案

您可以通过二进制计数的魔术来实现此目的。这些列中的每一列都是不同数字的二进制表示形式。就像任何解决方案一样,这样做有一些局限性,因为不可能有所有唯一的列。

d = np.arange(input_dim)
random.shuffle(d)
train_data = (((d[:,None] & (1 << np.arange(batch)))) > 0).astype(float).T
print( train_data )

答案 3 :(得分:1)

您最好的选择是将np.unpackbits与python的random.sample结合使用。 random.sample将采样而不替换,而不会创建输入列表。这意味着您可以在任意大整数上使用range对象,只要样本大小适合内存,就不会有问题的风险。 np.unpackbits然后将整数转换为唯一的位序列。这个想法是@ScottHunter's answer的具体实现。

batch_size = number_of_bits
input_size = number_of_samples

首先,确定您需要生成多少个字节,以及覆盖范围所需的最大整数。请记住,Python支持任意精度的整数,所以请发疯:

bytes_size = np.ceil(batch_size / 8)
max_int = 1<<batch_size

现在获取您的独特样品:

samples = random.sample(range(max_int), input_size)

Python整数是使用to_bytes方法的完整对象,它将为np.unpackbits准备样本:

data = np.array([list(x.to_bytes(bytes_size, 'little')) for x in samples], dtype=np.uint8).T

如果batch_size不是8的倍数,则字节顺序很重要:要修剪最终数组的大小。

现在打开包装,您就可以开始了:

result = np.unpackbits(data, axis=0)[:batch, :]

将所有内容放到一个包中

def random_bit_columns(batch_size, input_size):
    samples = random.sample(range(1 << batch_size), input_size)
    data = np.array([list(x.to_bytes(np.ceil(batch_size / 8), 'little')) for x in samples], dtype=np.uint8).T
    result = np.unpackbits(data, axis=0)[:batch, :]
    return result

如果您想利用python的任意精度整数的好处,恐怕我看不出对列数使用列表理解的方法。