将结构化 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 数据帧的主要内容,如果未能解决你的问题,请参考以下文章

将numpy结构化数组子集转换为numpy数组而不复制

列表列表到 numpy 数组中

将 NumPy 数组转换为 Python 列表结构?

如何将包含字符串列表的 numpy 数组转换为包含零和一列表的数组?

如何将 4D numpy 数组重塑为 3D 数组

如何将 numpy 数组转换为标准 TensorFlow 格式?