高效地将numpy数组数组转换为pandas系列数组

Cla*_*lay 4 python arrays numpy pandas

如何有效地将 numpy 数组数组转换为数组列表?最终,我想让 pandas 系列数组成为数据框中的列。如果有更好的办法可以直接到达,那也很好。

以下可重现的代码解决了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))
Run Code Online (Sandbox Code Playgroud)

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

hpa*_*ulj 8

你的a

\n\n
In [2]: a = np.array([np.array([0,1,2,3]), np.array([4,5,6,7])])\n   ...: \n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

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

\n\n
In [3]: pd.DataFrame(a)     # dtypes int64\nOut[3]: \n   0  1  2  3\n0  0  1  2  3\n1  4  5  6  7\n
Run Code Online (Sandbox Code Playgroud)\n\n

但从中制作一系列会引发错误:

\n\n
In [4]: pd.Series(a)\n---------------------------------------------------------------------------\n...\nException: Data must be 1-dimensional\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
In [5]: pd.Series(a.tolist())\nOut[5]: \n0    [0, 1, 2, 3]\n1    [4, 5, 6, 7]\ndtype: object\nIn [6]: pd.Series(list(a))\nOut[6]: \n0    [0, 1, 2, 3]\n1    [4, 5, 6, 7]\ndtype: object\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
In [8]: Out[5][0]\nOut[8]: [0, 1, 2, 3]\nIn [9]: Out[6][0]\nOut[9]: array([0, 1, 2, 3])\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的经验是,a.tolist()速度相当快。 list(a)相当于[i for i in a];实际上它在第一个维度上迭代a,每次返回(在本例中)一个一维数组(行)。

\n\n
\n\n

让我们改变a为一维对象数据类型数组:

\n\n
In [14]: a = np.array([np.array([0,1,2,3]), np.array([4,5,6,7]), np.array([1]), None])\nIn [15]: a\nOut[15]: \narray([array([0, 1, 2, 3]), array([4, 5, 6, 7]), array([1]), None],\n      dtype=object)\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
In [16]: pd.Series(a)\nOut[16]: \n0    [0, 1, 2, 3]\n1    [4, 5, 6, 7]\n2             [1]\n3            None\ndtype: object\nIn [17]: Out[16][0]\nOut[17]: array([0, 1, 2, 3])\n
Run Code Online (Sandbox Code Playgroud)\n\n

事实上我们可以用一部分来制作一个系列a,其中仅包含原始的 2 行:

\n\n
In [18]: pd.Series(a[:2])\nOut[18]: \n0    [0, 1, 2, 3]\n1    [4, 5, 6, 7]\ndtype: object\n
Run Code Online (Sandbox Code Playgroud)\n\n

构造 1d 对象 dtype 数组的技巧已在其他 SO 问题中深入讨论。

\n\n

请注意,像这样的 Series 的行为与多列 DataFrame 不同。我见过编写 csv 文件的尝试,其中类似的元素被保存为带引号的字符串。

\n\n
\n\n

让我们比较一些构建时间:

\n\n

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

\n\n
In [25]: a0 = np.ones([1000,4],int)\nIn [26]: a1 = np.empty(1000, object)\nIn [27]: a1[:] = [np.ones(4,int) for _ in range(1000)]\n# a1[:] = list(a0)   # faster\n
Run Code Online (Sandbox Code Playgroud)\n\n

首先制作一个DataFrame:

\n\n
In [28]: timeit pd.DataFrame(a0)\n136 \xc2\xb5s \xc2\xb1 919 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 10000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

像你一样制作一个系列:

\n\n
In [29]: timeit pd.Series(list(a0))\n434 \xc2\xb5s \xc2\xb1 12.9 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000 loops each)\nIn [30]: timeit pd.Series(a0.tolist())\n315 \xc2\xb5s \xc2\xb1 5.64 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

对于一维对象数组:

\n\n
In [31]: timeit pd.Series(a1)\n103 \xc2\xb5s \xc2\xb1 1.66 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

现在构建a1数组的速度变慢了。

\n\n

对象数组a1在很多方面就像列表一样 - 它包含指向内存中其他位置的对象的指针。如果元素类型不同(例如包含字符串或 None),它可能很有用,但从计算角度来说,它并不等同于二维数组。

\n\n
\n\n

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

\n