【问题标题】:Cannot cast array data from dtype('float64') to dtype('int32') according to the rule 'safe'无法根据规则“安全”将数组数据从 dtype('float64') 转换为 dtype('int32')
【发布时间】:2018-08-07 19:49:15
【问题描述】:

我有一个像

这样的 numpy 数组
result = np.array([[[289, 354, 331],
                    [291, 206,  66],
                    [242,  70, 256]],

                   [[210, 389, 342],
                    [273, 454, 218],
                    [255,  87, 256]],

                   [[127, 342, 173],
                    [450, 395, 147],
                    [223, 228, 401]]])

如果元素大于 255,我会尝试屏蔽数组。即我假设它的范围为 0-1024,然后将我的值除以 4

result = np.putmask(result, result > 255, result/4)

注意:结果是之前的 3D 数组。我得到了这个错误

TypeError: Cannot cast array data from dtype('float64') to dtype('int32') according to the rule 'safe'

我做错了什么? 提前致谢

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    错误说明:

    这说明了 numpy 数组的一个有趣属性:numpy 数组的所有元素必须属于同一类型

    例如,如果您有以下数组:

    >>> array1 = np.array([[23, 632, 634],[23.5, 67, 123.6]])
    >>> array1
    array([[  23. ,  632. ,  634. ],
       [  23.5,   67. ,  123.6]])
    >>> type(array1[0][0])
    <class 'numpy.float64'>
    

    我们注意到,即使列表 [23, 632, 634] 中的所有元素都是 int 类型(特别是 'numpy.int64'), array1 中的所有元素都被转换为浮点数,因为第二行中的元素 123.6 (注意数组中的小数点打印出来)。

    类似地,如果我们在数组的任何位置都包含一个字符串,那么数组的所有元素都会转换为字符串:

    >>> array2 = np.array([[23, 632, 'foo'],[23.5, 67, 123.6]])
    >>> type(array2[0][0])
    <class 'numpy.str_'>
    

    结论:

    您的原始 result 数组包含 'numpy.int64' 类型的元素,但 result/4 操作返回一个 'numpy 类型的元素数组。 float64'(因为 82 / 4 = 20.5 等)。因此,当您尝试替换 result 中的值时,它并不“安全”,因为您无意中尝试将浮点数放入整数数组中。

    【讨论】:

      【解决方案2】:

      问题是当你除以 4 时,你正在创建浮点值,它不想进入ints 的数组。

      如果您想使用putmask,并避免尝试转换为浮点数的问题,那么您可以使用地板除法(//)将您的值更改为int

      np.putmask(result, result>255, result//4)
      
      >>> result
      array([[[ 72,  88,  82],
              [ 72, 206,  66],
              [242,  70,  64]],
      
             [[210,  97,  85],
              [ 68, 113, 218],
              [255,  87,  64]],
      
             [[127,  85, 173],
              [112,  98, 147],
              [223, 228, 100]]])
      

      备选方案#1:

      将您的result 数组转换为浮点数dtype,并使用您原来的putmask

      result = result.astype(float)
      
      np.putmask(result, result > 255, result/4)
      
      >>> result
      array([[[ 72.25,  88.5 ,  82.75],
              [ 72.75, 206.  ,  66.  ],
              [242.  ,  70.  ,  64.  ]],
      
             [[210.  ,  97.25,  85.5 ],
              [ 68.25, 113.5 , 218.  ],
              [255.  ,  87.  ,  64.  ]],
      
             [[127.  ,  85.5 , 173.  ],
              [112.5 ,  98.75, 147.  ],
              [223.  , 228.  , 100.25]]])
      

      如果需要,您甚至可以在之后转换回 int:

      result = result.astype(int)
      
      array([[[ 72,  88,  82],
              [ 72, 206,  66],
              [242,  70,  64]],
      
             [[210,  97,  85],
              [ 68, 113, 218],
              [255,  87,  64]],
      
             [[127,  85, 173],
              [112,  98, 147],
              [223, 228, 100]]])
      

      备选方案#2:

      完全取消putmask,您可以获得您想要的结果,如下所示:

      result[result > 255] = result[result > 255] / 4
      
      >>> result
      array([[[ 72,  88,  82],
              [ 72, 206,  66],
              [242,  70,  64]],
      
             [[210,  97,  85],
              [ 68, 113, 218],
              [255,  87,  64]],
      
             [[127,  85, 173],
              [112,  98, 147],
              [223, 228, 100]]])
      

      【讨论】:

      • 是的。那行得通,谢谢。但是有什么办法可以解决我遇到的问题?
      • 查看我建议的第一种方法(在我编辑的帖子中),我试图解释发生了什么。