【问题标题】:How to create a numpy array of lists?如何创建一个numpy列表数组?
【发布时间】:2016-03-03 04:06:18
【问题描述】:

我想创建一个 numpy 数组,其中每个元素都必须是一个列表,以便稍后我可以将新元素附加到每个元素。

我已经在谷歌和这里查看过堆栈溢出,但似乎无处可寻。

主要问题是 numpy 假设您的列表必须成为一个数组,但这不是我想要的。

【问题讨论】:

  • 为什么不创建一个二维数组?
  • 为什么是numpy 列表数组?为什么不列出numpy 数组?还是列表?
  • 我有特殊要求。
  • 请详细说明您的“特殊要求”。如果您主要关心的是追加操作的速度,那么您不能比常规的 Python 列表做得更好,因为与数组串联相比,追加到列表非常便宜。但是,假设您想对列表执行数字运算,这会带来很大的存储和性能成本。每个子列表的长度是否相同,或者您是否尝试表示具有不同行长度的“参差不齐”的数组?
  • @ali_m,稀疏图的邻接列表。我需要操作为 O(m+n)。列表的列表杀死了它。此外,每个列表可能有不同的大小。我需要第一个向量是一个 O(1) 的数组,用于访问每个元素,然后是一个列表,在给定列表的每个元素的 O(d_max) 处访问它。

标签: python arrays list numpy


【解决方案1】:

如果您不需要 Pandas,我意识到这是一种解决方法,但它可以实现既定目标:

import pandas as pd

A = pd.Series([[1, 2], [3, 4]]).to_numpy()
assert isinstance(A[0], list)

【讨论】:

    【解决方案2】:

    如果您需要从一系列列表或元组中创建数组的数组

    x=[[1,2],[3,4],[5,6]]
    print(type(x))
    print(type(x[0]))
    #<class 'list'>
    #<class 'list'>
    import numpy as np
    ar=np.array([np.array(i) for i in x],dtype=object)
    print(type(ar))
    print(type(ar[0]))
    #<class 'numpy.ndarray'>
    #<class 'numpy.ndarray'>
    

    【讨论】:

      【解决方案3】:

      刚刚发现这个,我以前从未回答过问题,但这里有一个非常简单的解决方案:

      如果你想要一个长度为 n 的向量,请使用:

      A = np.array([[]]*n + [[1]])[:-1]
      

      这会返回:

      array([list([]), list([]), ... , list([])], dtype=object)
      

      如果您想要一个 n x m 数组,请使用:

      A = np.array([[]]*n*m + [[1]])[:-1]
      B = A.reshape((n,m))
      

      对于更高等级的数组,您可以通过创建一个长向量并对其进行整形来使用类似的方法。这可能不是最有效的方法,但它对我有用。

      【讨论】:

      • 运行这个会给我一个错误,除非你添加 dtype=object
      【解决方案4】:

      无论如何,列表并不是很简单,所以也许一个列表元组对你来说已经足够了。您可以使用迭代器表达式轻松高效地获得它:

      fiveLists = tuple([] for _ in range(5))
      

      如果您只需要一次 tuple,则可以省略它(为您提供原始迭代器)。

      如果你真的想要,你可以使用它来创建一个 numpy 数组:

      arrayOfLists = np.fromiter(([] for _ in range(5)), object)
      

      编辑:截至 2020 年 7 月,您将获得 "ValueError: 无法从迭代器创建对象数组"

      【讨论】:

        【解决方案5】:
        data = np.empty(20, dtype=np.object)
        for i in range(data.shape[0]):
            data[i] = []
            data[i].append(i)
        print(data)
        

        结果将是:

        [list([0]) list([1]) list([2]) list([3]) list([4]) list([5]) list([6]) list([7]) list([8]) list([9]) list([10]) list([11]) list([12]) list([13]) list([14]) list([15]) list([16]) list([17]) list([18]) list([19])]
        

        【讨论】:

          【解决方案6】:

          一个简单的方法是:

          A = [[1,2],[3,4]] 
          B = np.array(A+[[]])[:-1]
          

          【讨论】:

            【解决方案7】:

            正如您所发现的,np.array 在给出类似的东西时会尝试创建一个二维数组

             A = np.array([[1,2],[3,4]],dtype=object)
            

            你已经应用了一些技巧来绕过这个默认行为。

            一种是使子列表的长度可变。它不能从这些组成一个二维数组,所以它求助于对象数组:

            In [43]: A=np.array([[1,2],[],[1,2,3,4]])
            In [44]: A
            Out[44]: array([[1, 2], [], [1, 2, 3, 4]], dtype=object)
            

            然后您可以将值附加到每个列表中:

            In [45]: for i in A: i.append(34)
            In [46]: A
            Out[46]: array([[1, 2, 34], [34], [1, 2, 3, 4, 34]], dtype=object)
            

            np.empty 也创建了一个对象数组:

            In [47]: A=np.empty((3,),dtype=object)
            In [48]: A
            Out[48]: array([None, None, None], dtype=object)
            

            但是您必须小心如何将元素更改为列表。 np.fill很诱人,但有问题:

            In [49]: A.fill([])
            In [50]: A
            Out[50]: array([[], [], []], dtype=object)
            In [51]: for i in A: i.append(34)
            In [52]: A
            Out[52]: array([[34, 34, 34], [34, 34, 34], [34, 34, 34]], dtype=object)
            

            事实证明fill 在所有插槽中都放置了相同的列表,因此修改一个会修改所有其他的。使用列表列表也会遇到同样的问题:

            In [53]: B=[[]]*3
            In [54]: B
            Out[54]: [[], [], []]
            In [55]: for i in B: i.append(34)
            In [56]: B
            Out[56]: [[34, 34, 34], [34, 34, 34], [34, 34, 34]]
            

            初始化empty A 的正确方法是迭代,例如

            In [65]: A=np.empty((3,),dtype=object)
            In [66]: for i,v in enumerate(A): A[i]=[v,i]
            In [67]: A
            Out[67]: array([[None, 0], [None, 1], [None, 2]], dtype=object)
            In [68]: for v in A: v.append(34)
            In [69]: A
            Out[69]: array([[None, 0, 34], [None, 1, 34], [None, 2, 34]], dtype=object)
            

            问题和 cmets 有点不清楚您是要追加到列表还是将列表追加到数组。我刚刚演示了附加到列表。

            有一个np.append 功能,新用户经常误用它。它不能替代列表附加。它是np.concatenate 的前端。这不是就地操作;它返回一个新数组。

            同时定义一个要添加的列表可能很棘手:

            In [72]: np.append(A,[[1,23]])
            Out[72]: array([[None, 0, 34], [None, 1, 34], [None, 2, 34], 1, 23],     dtype=object)
            

            您需要构造另一个对象数组以连接到原始数组,例如

            In [76]: np.append(A,np.empty((1,),dtype=object))
            Out[76]: array([[None, 0, 34], [None, 1, 34], [None, 2, 34], None], dtype=object)
            

            在所有这一切中,列表数组比列表列表更难构建,并且操作起来并不容易或更快。您必须将其设为二维列表数组才能获得一些好处。

            In [78]: A[:,None]
            Out[78]: 
            array([[[None, 0, 34]],
                   [[None, 1, 34]],
                   [[None, 2, 34]]], dtype=object)
            

            您可以对对象数组进行整形、转置等操作,而创建和操作列表列表变得更加复杂。

            In [79]: A[:,None].tolist()
            Out[79]: [[[None, 0, 34]], [[None, 1, 34]], [[None, 2, 34]]]
            

            ===

            https://stackoverflow.com/a/57364472/901925所示,np.frompyfunc是创建对象数组的好工具。

            np.frompyfunc(list, 0, 1)(np.empty((3,2), dtype=object))  
            

            【讨论】:

            • 按摩我的数据后,如何将这个数组数组转换回常规的 numpy 数组? (假设内部数组现在都是相同的形状)
            • @evn,concatenate 的某些版本可以将数组重新合并为一个。 np.stack() 通常是一个不错的选择。确保外部数组是 1d,因为他们将其视为数组列表。
            【解决方案8】:

            如果你真的需要一个一维列表数组,你必须将你的列表包装在你自己的类中,因为 numpy 总是会尝试将你的列表转换为数组内的数组(这更有效,但显然需要常量大小-elements),例如通过

            class mylist:
            
                def __init__(self, l):
                    self.l=l
            
                def __repr__(self): 
                    return repr(self.l)
            
                def append(self, x):
                    self.l.append(x)
            

            然后你可以改变任何元素而不改变其他元素的维度

            >>> x = mylist([1,2,3])
            >>> y = mylist([1,2,3])
            >>> import numpy as np
            >>> data = np.array([x,y])
            >>> data
            array([[1,2,3], [1,2,3]], dtype=object)
            >>> data[0].append(2)
            >>> data
            array([[1,2,3,2], [1,2,3]], dtype=object)
            

            更新

            正如ali_m 所建议的,实际上有一种方法可以强制 numpy 简单地为引用创建一个一维数组,然后用实际列表提供它们

            >>> data = np.empty(2, dtype=np.object)
            >>> data[:] = [1, 2, 3], [1, 2, 3]
            >>> data
            array([[1, 2, 3], [1, 2, 3]], dtype=object)
            >>> data[0].append(4)
            >>> data
            array([[1, 2, 3, 4], [1, 2, 3]], dtype=object)
            

            【讨论】:

            • 在我的情况下,我不知道我将拥有多少个我的列表,一般情况下如何?
            • 您可以在不使用data = np.empty(2, dtype=np.object); data[:] = [1, 2, 3], [1, 2, 3]定义新类的情况下获得相同的结果
            • @Ricardo 如果你不知道你有多少个列表,那么你为什么要首先使用数组?它们是固定大小。如果您想在旅途中添加列表,那么列表列表可能更可取。否则 - 你总是可以使用np.concatenate 来合并数组
            • 一个有趣的观察@lejlot 和对其他寻找捷径的人的警告......不要忘记 data = np.empty(2, dtype=np.object) 创建行。如果您尝试使用 ... data = np.array([[1,2,3],[4,5,6]],dtype=np.object) ... 明显地跳过一个步骤 ... 然后尝试 . .. data[0].append(4) 它将返回... AttributeError: 'numpy.ndarray' object has no attribute 'append' in python 3.4.x 。显然需要先创建一个空对象数组,然后是填充。
            • np.append 只是调用np.concatenate 的另一种方式。它不是列表追加的克隆。
            猜你喜欢
            • 1970-01-01
            • 2021-11-22
            • 2021-02-02
            • 2020-04-03
            • 2019-06-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-03-17
            相关资源
            最近更新 更多