Преобразовать структурированный массив numpy (содержащий подмассивы) в pandas dataframe - PullRequest
1 голос
/ 13 марта 2020

Проблема

В качестве примера рассмотрим следующий структурированный массив 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 фрейм данных?

Ответы [ 3 ]

1 голос
/ 13 марта 2020

Вы можете сделать (при условии, что вы знаете, что столбец 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
1 голос
/ 13 марта 2020
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')])

Похоже, что newi sh structure_to_unstructured может обработать этот тип d:

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
1 голос
/ 13 марта 2020

Это можно сгладить с помощью двух 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
...