【问题标题】:Efficiently convert numpy array of arrays to pandas series of arrays高效地将numpy数组转换为pandas数组
【发布时间】:2018-08-05 03:31:53
【问题描述】:

如何有效地将 numpy 数组的 numpy 数组转换为数组列表?最终,我想让一个熊猫系列数组成为一个列是一个数据框。如果有更好的方法可以直接实现这一点,那也很好。

以下可重现的代码解决了list().tolist() 的问题,但在我的实际数据集上实现这两种代码都太慢了。我正在寻找更快的东西。

import numpy as np 
import pandas as pd

a = np.array([np.array([0,1,2,3]), np.array([4,5,6,7])])

s = pd.Series(a.tolist())

s = pd.Series(list(a))

这导致形状从a.shape = (2,4) 变为s.values.shape = (2,)

【问题讨论】:

  • 为什么不pd.DataFrame(a)
  • a 是二维数组,(2,4)。不是数组数组(除非您首先进行了构造 (2,) 形状对象数组的额外工作)。那应该映射到一个 4 列的 DataFrame。或者你真的想要一个系列,其中每个元素都是一个数组(和对象 dtype)?我认为这不会是efficient 系列。这不是一个高效的array
  • @hpaulj - 是的,我“想要一个系列,其中每个元素都是一个数组。”
  • @miradulo 会为嵌套数组中的每个元素生成一个单独的列。我希望生成的数据框有一列,其中每一行都有a 的嵌套数组之一。
  • 你知道如何制作一个包含数组的一维数组吗?对象 dtyoe?您的示例 a 不符合条件。尝试改变子数组长度,或包含None

标签: python arrays pandas numpy


【解决方案1】:

你的a

In [2]: a = np.array([np.array([0,1,2,3]), np.array([4,5,6,7])])
   ...: 

a 是 (2,4) 数值数组;我们本来可以写a = np.array([[0,1,2,3],[4,5,6,7]])。创建一个 (2,) 数组需要不同的构造。

正如其他人所写,制作数据框很简单:

In [3]: pd.DataFrame(a)     # dtypes int64
Out[3]: 
   0  1  2  3
0  0  1  2  3
1  4  5  6  7

但是用它制作一个系列会引发错误:

In [4]: pd.Series(a)
---------------------------------------------------------------------------
...
Exception: Data must be 1-dimensional

如果显示此错误,您的问题会更清楚,以及为什么您尝试使用列表输入:

In [5]: pd.Series(a.tolist())
Out[5]: 
0    [0, 1, 2, 3]
1    [4, 5, 6, 7]
dtype: object
In [6]: pd.Series(list(a))
Out[6]: 
0    [0, 1, 2, 3]
1    [4, 5, 6, 7]
dtype: object

表面上它们是相同的,但是当我们查看 Series 的实际元素时,我们会看到一个包含列表,另一个包含数组。这是因为 tolistlist() 从数组中创建了不同的列表。

In [8]: Out[5][0]
Out[8]: [0, 1, 2, 3]
In [9]: Out[6][0]
Out[9]: array([0, 1, 2, 3])

我的经验是a.tolist() 相当快。 list(a) 等价于[i for i in a];实际上,它迭代a 的第一个维度,每次返回(在这种情况下)一个一维数组(行)。


让我们更改a,使其成为一维对象 dtype 数组:

In [14]: a = np.array([np.array([0,1,2,3]), np.array([4,5,6,7]), np.array([1]), None])
In [15]: a
Out[15]: 
array([array([0, 1, 2, 3]), array([4, 5, 6, 7]), array([1]), None],
      dtype=object)

现在我们可以用它制作一个系列:

In [16]: pd.Series(a)
Out[16]: 
0    [0, 1, 2, 3]
1    [4, 5, 6, 7]
2             [1]
3            None
dtype: object
In [17]: Out[16][0]
Out[17]: array([0, 1, 2, 3])

事实上,我们可以从a 的切片中创建一个系列,该切片仅包含原始的 2 行:

In [18]: pd.Series(a[:2])
Out[18]: 
0    [0, 1, 2, 3]
1    [4, 5, 6, 7]
dtype: object

构建一维对象 dtype 数组的技巧已在其他 SO 问题中进行了深入讨论。

请注意,这样的系列不像多列 DataFrame。我看到有人尝试编写 csv 文件,其中像这样的元素被保存为带引号的字符串。


让我们比较一些施工时间:

制作 2 种类型的更大数组:

In [25]: a0 = np.ones([1000,4],int)
In [26]: a1 = np.empty(1000, object)
In [27]: a1[:] = [np.ones(4,int) for _ in range(1000)]
# a1[:] = list(a0)   # faster

首先制作一个DataFrame:

In [28]: timeit pd.DataFrame(a0)
136 µs ± 919 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

这与Out[3]的时间相同;显然只是使用 2d 数组(任何大小)作为 values 制作 DataFrame 的开销。

像你一样制作一个系列:

In [29]: timeit pd.Series(list(a0))
434 µs ± 12.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [30]: timeit pd.Series(a0.tolist())
315 µs ± 5.64 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

这两个都比小的a长,反映了创作的迭代性质。

并使用一维对象数组:

In [31]: timeit pd.Series(a1)
103 µs ± 1.66 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

这与小型一维数组相同。与In[28] 一样,我认为创建Series 对象,然后为其分配一个未更改的值数组只是开销。

现在构造a1 数组的速度较慢。

a1 这样的对象数组在很多方面就像一个列表——它包含指向内存中其他地方的对象的指针。如果元素类型不同(例如包含字符串或无),它可能很有用,但在计算上它不等同于二维数组。


总而言之,如果源数组确实是一维对象 dtype 数组,您可以从中快速创建一个Series。如果它真的是一个二维数组,您需要先以某种方式将其转换为列表或一维对象数组。

【讨论】:

    【解决方案2】:

    您可以从普通长度列表或列表列表的 dict 中制作 DataFrame。在前一种情况下,pandas 将键转换为列名,将列表转换为列值,在后一种情况下,每个列表都被视为行。

    import numpy as np 
    import pandas as pd
    
    a = np.array([np.array([0,1,2,3]), np.array([4,5,6,7])])
    df = pd.DataFrame()
    df['a'] = a.tolist()
    df
    

    输出:

        a
    0   [0, 1, 2, 3]
    1   [4, 5, 6, 7]
    

    【讨论】:

    • 感谢@krishna,但我需要数据框的每一行 one 列包含a 的每个子数组。
    • @Clay 第 1 行应该是 [0,4] 而第 2 行应该是 [1,5]?
    • 不,第 1 行第 1 列应为 array([0,1,2,3]),第 2 行第 1 列应为 array([4,5,6,7])。如果您可以先从a 创建一个数据框,然后在不使用 for 循环的情况下将每一行转换为新列中的数组,那应该可以。
    • 这正是我在原始问题中给出的解决方案,但对于大型数据集来说会变慢。
    • pd.DataFrame({'a':a.tolist()})?
    猜你喜欢
    • 2019-10-30
    • 2019-08-04
    • 2020-02-10
    • 1970-01-01
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 2015-12-04
    相关资源
    最近更新 更多