【问题标题】:numpy.concatenate on record arrays fails when array has different length strings当数组具有不同长度的字符串时,记录数组上的 numpy.concatenate 失败
【发布时间】:2012-08-23 11:16:29
【问题描述】:

当尝试连接具有 dtype 字符串字段但长度不同的记录数组时,连接失败。

如您在以下示例中所见,如果 'f1' 的长度相同,则连接有效,但如果不是,则连接失败。

In [1]: import numpy as np

In [2]: a = np.core.records.fromarrays( ([1,2], ["one","two"]) )

In [3]: b = np.core.records.fromarrays( ([3,4,5], ["three","four","three"]) )

In [4]: c = np.core.records.fromarrays( ([6], ["six"]) )

In [5]: np.concatenate( (a,c) )
Out[5]: 
array([(1, 'one'), (2, 'two'), (6, 'six')], 
      dtype=[('f0', '<i8'), ('f1', '|S3')])

In [6]: np.concatenate( (a,b) )
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/u/jegannas/<ipython console> in <module>()

TypeError: expected a readable buffer object

但是,如果我们只是连接数组(而不是记录),它会成功,尽管字符串的大小不同。

In [8]: np.concatenate( (a['f1'], b['f1']) )
Out[8]: 
array(['one', 'two', 'three', 'four', 'three'], 
      dtype='|S5')

这是连接记录时连接中的错误还是预期的行为。我想出了以下方法来克服这个问题。

In [10]: np.concatenate( (a.astype(b.dtype), b) )
Out[10]: 
array([(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'three')], 
      dtype=[('f0', '<i8'), ('f1', '|S5')]

但是这里的问题是我必须遍历所有的recarrays,我正在连接并找到最大的字符串长度,我必须使用它。如果记录数组中有多个字符串列,我还需要跟踪其他一些事情。

你认为克服这个问题的最好方法是什么,至少目前是这样?

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    发布完整的答案。正如 Pierre GM 建议的模块:

    import numpy.lib.recfunctions
    

    给出一个解决方案。然而,你想要的功能是:

    numpy.lib.recfunctions.stack_arrays((a,b), autoconvert=True, usemask=False)
    

    (usemask=False 只是为了避免创建您可能没有使用的掩码数组。重要的是autoconvert=True 强制从adtype "|S3" 转换为@987654328 @)。

    【讨论】:

      【解决方案2】:

      numpy.lib.recfunctions.merge_arrays 适合你吗? recfunctions 是一个鲜为人知的子包,它没有被大量宣传,它有点笨拙但有时可能很有用。

      【讨论】:

      • 这里的numpy版本是什么。我没有看到这个。
      • @SenthilBabu 你必须明确地导入它import numpy.lib.recfunctions。 (除此之外它至少存在于 1.6
      • 我不认为,我需要mergearrays。只有当我有未定义的值时它才有用。否则。 mergearrays 等同于 numpy.core.records.fromarrays
      • 确实,不过也有 stack_arrays 有 autoconvert 关键字:numpy.lib.recfunctions.stack_arrays((a,b), autoconvert=True, usemask=False)
      【解决方案3】:

      当您不指定数据类型时,np.rec.fromarrays(又名np.core.records.fromarrays)会尝试为您猜测数据类型。因此,

      In [4]: a = np.core.records.fromarrays( ([1,2], ["one","two"]) )
      
      In [5]: a
      Out[5]: 
      rec.array([(1, 'one'), (2, 'two')], 
            dtype=[('f0', '<i4'), ('f1', '|S3')])
      

      请注意,f1 列的 dtype 是一个 3 字节的字符串。

      您不能连接 np.concatenate( (a,b) ),因为 numpy 发现 ab 的 dtype 不同,并且不会更改较小字符串的 dtype 以匹配较大的字符串。

      如果您知道适用于所有数组的最大字符串大小,则可以从头开始指定 dtype:

      In [9]: a = np.rec.fromarrays( ([1,2], ["one","two"]), dtype = [('f0', '<i4'), ('f1', '|S8')])
      
      In [10]: b = np.core.records.fromarrays( ([3,4,5], ["three","four","three"]), dtype = [('f0', '<i4'), ('f1', '|S8')])
      

      然后连接将按需要工作:

      In [11]: np.concatenate( (a,b))
      Out[11]: 
      array([(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'three')], 
            dtype=[('f0', '<i4'), ('f1', '|S8')])
      

      如果您事先不知道字符串的最大长度,可以将 dtype 指定为 'object':

      In [35]: a = np.core.records.fromarrays( ([1,2], ["one","two"]), dtype = [('f0', '<i4'), ('f1', 'object')])
      
      In [36]: b = np.core.records.fromarrays( ([3,4,5], ["three","four","three"]), dtype = [('f0', '<i4'), ('f1', 'object')])
      
      In [37]: np.concatenate( (a,b))
      Out[37]: 
      array([(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four'), (5, 'three')], 
            dtype=[('f0', '<i4'), ('f1', '|O4')])
      

      这不会像 '|Sn' 的 dtype(对于某些整数 n)那样节省空间,但至少它允许您执行 concatenate 操作。

      【讨论】:

      • 我知道。这就是我的问题本身。所有这些单独的数组都是由一个子模块(我无法控制)生成的。我只需要连接所有这些数组。
      • 我建议您提前选择一个足以容纳所有字符串的数字n,而不是跟踪每个数组的最大大小。这与您在问题中提出的想法不同。但是,如果无法提前知道这样的数字 n,则可以改用 'object' dtype。我也编辑了我的帖子来证明这一点。
      猜你喜欢
      • 2014-02-28
      • 2018-06-21
      • 1970-01-01
      • 2019-12-17
      • 2023-01-26
      • 1970-01-01
      • 1970-01-01
      • 2015-05-02
      • 1970-01-01
      相关资源
      最近更新 更多