python2.7 - 写入磁盘时将布尔值存储为单独的位

时间:2016-07-27 20:14:52

标签: python numpy

我正在编写将整数转换为填充的8位字符串的代码。然后我想将这些字符串写入二进制文件。我在找出与我目前正在使用的numpy数组一起使用的正确dtype时遇到了问题。

在以下代码中,当bin_data变量设置为dtype=np.int8时,输出为:

$ python bool_dtype.py 
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 1, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
[0 0 0 0 1 0 0 0 0]
16

bin_data设置为dtype=np.bool_时,输出始终为true,如下所示:

$ python bool_dtype.py 
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 1, bool(a[j]) = True
a[j] = 1, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 0, bool(a[j]) = True
a[j] = 1, bool(a[j]) = True
a[j] = 1, bool(a[j]) = True
[ True  True  True  True  True  True  True  True  True]
16

当我在使用dtype=np.int8时查看数据的xxd转储时,我看到一个预期字节用于表示每个位(1,0)IE 00000001或00000000.使用dtype=np.bool_导致同样的问题。

所以我遇到的两个主要问题是

  1. 为什么bool在读取数组元素时总是读为True

  2. 如何在将数据写入文件时更有效地存储数据,使得单个位存储为字节,而只是连接到前一个元素上?

  3. 以下是有问题的代码,谢谢!

    #!/usr/bin/python2.7
    
    import numpy as np
    import os
    
    # x = np.zeros(200,dtype=np.bool_)
    # for i in range(0,len(x)):
    #     if i%2 != 1:
    #         x[i] = 1
    
    data_size = 2
    data = np.random.randint(0,9,data_size)
    tx=''
    for i in range(0,data_size):
        tx += chr(data[i])
    data = tx
    a = np.zeros(8,dtype=np.int8)
    bin_data = np.zeros(len(data)*8,dtype=np.bool_)
    
    # each i is a character byte in data string
    for i in range(0,len(data)):
        # formats data in 8bit binary without the 0b prefix
        a = format(ord(data[i]),'b').zfill(8)
        for j in range(0,len(a)):
            bin_data[i*len(a) + j] = a[j]
            print("a[j] = {}, bool(a[j]) = {}").format(a[j], bool(a[j]))
    
    print bin_data[1:10]
    print len(bin_data)
    
    path = os.getcwd()
    path = path + '/bool_data.bin'
    data_file = open(path, "wb")
    data_file.write(bin_data)
    data_file.close()
    

    编辑:

    使用dtype=np.bool_

    时,我希望看到的内容
    >>> import numpy as np
    >>> a = np.zeros(2,dtype=np.bool_)
    >>> a
    array([False, False], dtype=bool)
    >>> a[1] = 1
    >>> a
    array([False,  True], dtype=bool)
    

1 个答案:

答案 0 :(得分:5)

  1. bool始终返回true的原因是a [j]是非空的字符串。在使用bool进行测试之前(以及在将其指定为numpy bool数组的条目之前),需要将[j]强制转换为int。
  2. 您可以调用numpy.packbits将您的布尔数组压缩为uint8数组(如果需要,它会为您填充),然后调用numpy.unpackbits来反转操作。
  3. 修改:

    如果你的布尔数组的长度不是8的倍数,那么打包和解包后你的数组将被填零以使长度为8的倍数。在这种情况下,你有两个选择:

    1. 如果您可以安全地截断数据,使其具有可被8整除的位数,则执行此操作。类似于:data=data[:8*(len(data)/8)]
    2. 如果你不能截断,那么你将以某种方式记录有意义的位数。我建议使打包数据的第一个字节等于mod 8的有意义位数。这将只增加一个字节的内存开销,并且计算时间不多。类似的东西:
    3. 包装

      bool_data = np.array([True, True, True])
      nbits = len(bool_data)
      rem = nbits % 8
      nbytes = nbits/8
      if rem: nbytes += 1
      data = np.empty(1+nbytes, dtype=np.uint8)
      data[0] = rem
      data[1:] = np.packbits(bool_data)
      

      启封

      rem = data[0]
      bool_data = np.unpackbits(data[1:])
      if rem:
        bool_data = bool_data[:-(8-rem)]