如何将numpy数组的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))
这导致形状从a.shape = (2,4)
变为s.values.shape = (2,)
。
答案 0 :(得分:2)
您的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
从表面上看,它们是相同的,但是当我们查看系列的实际元素时,我们看到一个包含列表,另一个包含列表。这是因为tolist
和list()
从数组中创建了不同的列表。
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
的第一维上进行迭代,每次都返回(在这种情况下)一个1d数组(行)。
让我们更改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
在其他SO问题中已深入讨论了构造1d对象dtype数组的技巧。
请注意,这样的Series的行为不像多列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]
的时间相同;显然,制作带有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)
这与小型1d阵列相同。与In[28]
一样,我认为创建Series
对象,然后为其分配一个未更改的值数组只是开销。
现在构造a1
数组比较慢。
a1
之类的对象数组在许多方面都类似于列表,它包含指向内存中其他位置的对象的指针。如果元素的类型不同(例如,包括字符串或无),则可能很有用,但在计算上不等同于2d数组。
总而言之,如果源数组确实是1d对象dtype数组,则可以从中快速创建一个Series
。如果它确实是2d数组,则需要以某种方式将其首先转换为列表或1d对象数组。
答案 1 :(得分:0)
您可以从公共长度列表或列表列表的字典中制作DataFrame。在前一种情况下,大熊猫将键转换为列名,将列表转换为列值,在后一种情况下,每个列表均视为行。
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]