将结构化 numpy 数组(包含子数组)转换为 pandas 数据帧
Posted
技术标签:
【中文标题】将结构化 numpy 数组(包含子数组)转换为 pandas 数据帧【英文标题】:Convert structured numpy array (containing sub-arrays) to pandas dataframe 【发布时间】:2020-06-25 00:36:16 【问题描述】:问题
例如,考虑以下结构化 numpy 数组(包含子数组):
data = [
(1, (5., 3., 7.), 6),
(2, (2., 1., 3.), 9),
(3, (3., 8., 4.), 3),
(4, (1., 7., 4.), 2),
]
dtype = [('A', '<i8'), ('B', '<f8', (3,)), ('C', '<i8')]
arr = np.array(data, dtype=dtype)
我想将此数组 arr
转换为如下所示的 pandas 数据框:
A B_1 B_2 B_3 C
0 1 5.0 3.0 7.0 6
1 2 2.0 1.0 3.0 9
2 3 3.0 8.0 4.0 3
3 4 1.0 7.0 4.0 2
到目前为止尝试过
我尝试使用 pandas 的方法from_records
进行转换:
df = pd.DataFrame.from_records(arr)
但这会引发错误Exception: Data must be 1-dimensional
。
问题
什么是执行这种转换为 pandas 数据帧的好方法?
【问题讨论】:
【参考方案1】:这可以通过两个pd.DataFrame
调用来展平
df=pd.DataFrame(arr.tolist())
df=df.join(pd.DataFrame(df[1].tolist()).add_prefix('B'))
Out[404]:
0 1 2 B0 B1 B2
0 1 [5.0, 3.0, 7.0] 6 5.0 3.0 7.0
1 2 [2.0, 1.0, 3.0] 9 2.0 1.0 3.0
2 3 [3.0, 8.0, 4.0] 3 3.0 8.0 4.0
3 4 [1.0, 7.0, 4.0] 2 1.0 7.0 4.0
【讨论】:
【参考方案2】:您可以这样做(假设您知道,该列 B
是要扩展的列,如果您需要进一步自动化它,您可以迭代 dtype
- 以获得复合类型的列)
df=pd.DataFrame.from_records(map(lambda x: list(x), arr), columns=arr.dtype.names)
df2=pd.DataFrame(df["B"].tolist())
df2.columns=map(lambda x: f"B_x+1", df2.columns)
df=pd.concat([df, df2], sort=False, axis=1).drop(columns="B")
输出:
A C B_1 B_2 B_3
0 1 6 5.0 3.0 7.0
1 2 9 2.0 1.0 3.0
2 3 3 3.0 8.0 4.0
3 4 2 1.0 7.0 4.0
【讨论】:
【参考方案3】:In [56]: data = [
...: (1, (5., 3., 7.), 6),
...: (2, (2., 1., 3.), 9),
...: (3, (3., 8., 4.), 3),
...: (4, (1., 7., 4.), 2),
...: ]
...: dtype = [('A', '<i8'), ('B', '<f8', (3,)), ('C', '<i8')]
...: arr = np.array(data, dtype=dtype)
In [57]: arr
Out[57]:
array([(1, [5., 3., 7.], 6), (2, [2., 1., 3.], 9), (3, [3., 8., 4.], 3),
(4, [1., 7., 4.], 2)],
dtype=[('A', '<i8'), ('B', '<f8', (3,)), ('C', '<i8')])
看起来新的structure_to_unstructured
可以处理这个dtype:
In [59]: import numpy.lib.recfunctions as rf
In [60]: rf.structured_to_unstructured(arr)
Out[60]:
array([[1., 5., 3., 7., 6.],
[2., 2., 1., 3., 9.],
[3., 3., 8., 4., 3.],
[4., 1., 7., 4., 2.]])
然后以通常的方式制作数据框。
In [63]: pd.DataFrame(_60, columns=['A','B1','B2','B3','C'])
Out[63]:
A B1 B2 B3 C
0 1.0 5.0 3.0 7.0 6.0
1 2.0 2.0 1.0 3.0 9.0
2 3.0 3.0 8.0 4.0 3.0
3 4.0 1.0 7.0 4.0 2.0
并在列中添加 dtypes
In [74]: df = pd.DataFrame(_60, columns=['A','B1','B2','B3','C'])
In [75]: df['A']=df['A'].astype(int)
In [76]: df['C']=df['C'].astype(int)
In [77]: df
Out[77]:
A B1 B2 B3 C
0 1 5.0 3.0 7.0 6
1 2 2.0 1.0 3.0 9
2 3 3.0 8.0 4.0 3
3 4 1.0 7.0 4.0 2
【讨论】:
以上是关于将结构化 numpy 数组(包含子数组)转换为 pandas 数据帧的主要内容,如果未能解决你的问题,请参考以下文章