【问题标题】:Converting an array to a float, how to reverse the process?将数组转换为浮点数,如何反转过程?
【发布时间】:2015-03-21 10:31:47
【问题描述】:

假设我们从一个整数 numpy 数组开始,整数在 0 到 99 之间,即

x = np.array([[1,2,3,1],[10,5,0,2]],dtype=int)

现在我们想用一个唯一值来表示这个数组中的行。一种简单的方法是将其表示为浮点数。一种直观的方法是

rescale = np.power(10,np.arange(0,2*x.shape[1],2)[::-1],dtype=float)
codes = np.dot(x,rescale)

我们利用整数最多有 2 个数字。 (我将rescale 转换为浮点数以避免超过 int 的最大值,以防x 的条目有更多元素;这不是很优雅)

返回

array([  1020301.,  10050002.])

如何将这个过程反过来再次获得x

我正在考虑将codes 转换为字符串,然后每隔第二个条目拆分一次字符串。我对这些字符串操作不太熟悉,尤其是当它们必须同时在数组的所有条目上执行时。还有一个问题是第一个数字的位数不同,因此必须以某种方式添加尾随零。

也许使用一些除法或四舍五入可以实现更简单的操作,或者以不同的方式重新排列数组的行。重要的是,至少初始转换是快速且矢量化的。

欢迎提出建议。

【问题讨论】:

  • 您应该使用 100 而不是 10 的幂来定义重新缩放,并且您可以在创建它时直接反转范围而不是在取幂之后:rescale = np.power(100, np.arange(x.shape[0]-1, 0, -1), dtype=float)
  • @FrancisColas 太好了。在这里你需要x.shape[1],顺便说一句。
  • 是的,我刚刚复制了您的x.shape[0]。这实际上应该是np.arange(x.shape[1]-1, -1, -1)

标签: python arrays string numpy split


【解决方案1】:

首先,你需要找到正确的列数:

number_of_cols = max(ceil(math.log(v, 100)) for v in codes)

请注意,您的第一列始终为 0,那么您的代码甚至无法知道它是否存在:[[0, 1], [0, 2]] -> [1., 2.] -> [[1], [2]] or [[0, 0, 0, 1], [0, 0, 0, 2]]。这可能是需要考虑的事情。

不管怎样,这里有一个字符串方式的模型:

def decode_with_string(codes):
    number_of_cols = max(ceil(math.log(v, 100)) for v in codes)
    str_format = '{:0%dd}'%(2*number_of_cols) # prepare to format numbers as string
    return [[int(str_format.format(int(code))[2*i:2*i+2]) # extract the wanted digits
             for i in range(number_of_cols)] # for all columns
            for code in codes] # for all rows

但你也可以直接计算数字:

def decode_direct(codes):
    number_of_cols = max(ceil(math.log(v, 100)) for v in codes)
    return [[floor(code/(100**index)) % 100
             for index in range(number_of_cols-1, -1, -1)]
            for code in codes]

例子:

>>> codes = [  1020301.,  10050002.]
>>> number_of_cols = max(ceil(math.log(v, 100)) for v in codes)
>>> print(number_of_cols)
4
>>> print(decode_with_strings(codes))
[[1, 2, 3, 1], [10, 5, 0, 2]]
>>> print(decode_direct(codes))
[[1, 2, 3, 1], [10, 5, 0, 2]]

这是一个 numpy 解决方案:

>>> divisors = np.power(0.01, np.arange(number_of_cols-1, -1, -1))
>>> x = np.mod(np.floor(divisors*codes.reshape((codes.shape[0], 1))), 100)

最后,你说你使用float 以防int 溢出。首先,浮点数的尾数也是有限的,所以你没有消除溢出的风险。其次,在Python3中,整数实际上有unlimited precision

【讨论】:

  • 我正在寻找一个使用 numpy 的解决方案,它通常更快、更容易阅读。你是对的零。我实际上做的是向 numpy 数组添加一个常量以避免这种情况。
  • 我添加了一个与您的编码相反的 numpy 解决方案。
  • 太棒了!效果很好。我真的很想在这里接受这两个答案,但我想你的答案达到了我最想要的。
  • Dietrich 的回答实际上是提出了一种不同的方式来对您的值进行编码,而我只是提出了根据要求进行解码的方式。这可能只是XY problem 的一个实例。
  • 至于您对可读性和速度的要求,我建议您测试我提出的三种方法,看看哪个是最快的(为了可读性,这是您的选择)。
【解决方案2】:

您可以利用 Numpy 将其数组作为连续块存储在内存中。因此,将内存块存储为二进制字符串并记住数组的形状就足够了:

import numpy as np

x = np.array([[1,2,3,1],[10,5,0,2]], dtype=np.uint8) # 8 Bit are enough for 2 digits
x_sh = x.shape
# flatten array and convert to binarystring
xs = x.ravel().tostring()

# convert back and reshape:
y = np.reshape(np.fromstring(xs, np.uint8), x_sh)

之所以先扁平化数组,是因为不需要关注二维数组的存储顺序(C或FORTRAN顺序)。当然你也可以为每一行单独生成一个字符串:

import numpy as np

x = np.array([[1,2,3,1],[10,5,0,2]], dtype=np.uint8) # 8 Bit are enough for 2 digits

# conversion:
xss = [xr.tostring() for xr in x]

# conversion back:
y = np.array([np.fromstring(xs, np.uint8) for xs in xss])

【讨论】:

  • 第二种方法对我最有用。但是,对于我的程序,我确实需要一个矢量化版本,以便我可以快速计算数组的字符串并使用 np.searchsorted 将它们与存储的字符串进行比较。事实上我的x 是二维的。
  • 我不确定,我可以在这里关注你。在寻找z 时,np.searchsorted(xss, z.tostring()) 不符合您的要求吗?
  • 是的。但它使用列表推导来生成字符串,这通常比直接应用于所有向量的一些 numpy 方法要慢。
【解决方案3】:

由于您的数字介于 0 和 99 之间,因此您应该最多填充 2 位数字:0 变为“00”,5 变为“05”,50 变为“50”。这样,您需要做的就是反复将您的数字除以 100,您就会得到值。您的编码也会更小,因为每个数字都编码为 2 位数字,而不是像您目前所做的 2-3 位。

如果您还希望能够检测到 [0,0,0](目前无法与 [0] 或 [O.....O] 区分),请在您的号码前添加 1: 1000000 是 [0,0,0],100 是 [0]。当你的除法返回 1 时,你就知道你已经完成了。

您可以轻松地使用该信息构造一个字符串,然后将其转换为一个数字。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    • 2016-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多