如何使用list(例如dataclass)将多索引 Dataframe 转换为对象?

neskvpey  于 2021-09-08  发布在  Java
关注(0)|答案(2)|浏览(323)

首先,假设您有以下 Dataframe 。

import pandas as ps

df = ps.DataFrame([
    [0, 'test0', 0, 'sub0', 'one'],
    [0, 'test0', 1, 'sub1', 'two'],
    [1, 'test1', 0, 'sub0', 'one'],
    [1, 'test1', 1, 'sub1', 'two'],
], columns=['id', 'name', 'sub_id', 'sub_name', 'value'])

df = df.set_index(['id', 'sub_id'])
name sub_name value
id sub_id                      
0  0       test0     sub0   one
   1       test0     sub1   two
1  0       test1     sub0   one
   1       test1     sub1   two

我想将其转换为下面的列表对象(这里我们使用dataclass)。

from typing import List
from dataclasses import dataclass

@dataclass
class SubObj:
    id: int
    name: str
    value: str

@dataclass
class MainObj:
    id: int
    name: str
    sub_obj: List[SubObj]

输出应如下所示:

result = [
    MainObj(
        id=0,
        name='test0',
        sub_obj=[
            SubObj(
                id=0,
                name='sub0',
                value='one'
            ),
            SubObj(
                id=1,
                name='sub1',
                value='two'
            )
        ]
    ),
    MainObj(
        id=1,
        name='test1',
        sub_obj=[
            SubObj(
                id=0,
                name='sub0',
                value='one'
            ),
            SubObj(
                id=1,
                name='sub1',
                value='two'
            )
        ]
    ),
]

print(result)
[MainObj(id=0, name='test0', sub_obj=[SubObj(id=0, name='sub0', value='one'), SubObj(id=1, name='sub1', value='two')]), MainObj(id=1, name='test1', sub_obj=[SubObj(id=0, name='sub0', value='one'), SubObj(id=1, name='sub1', value='two')])]

我想实现它,以便它输出一个mainobj列表,其中包含尽可能短且易于理解的代码。
你知道怎么做吗?

3pvhb19x

3pvhb19x1#

这里有一个方法可以用Pandas来做
将行聚合到 SubObjsub_id 创建仅包含 MainObj 级别信息
将行聚合到 MainObj ```

sub = df.reset_index('sub_id')'sub_id', 'sub_name', 'value'.agg(lambda row: SubObj(*row), axis='columns')
sub
id
0 SubObj(id=0, name='sub0', value='one')
0 SubObj(id=1, name='sub1', value='two')
1 SubObj(id=0, name='sub0', value='one')
1 SubObj(id=1, name='sub1', value='two')
sub.groupby('id').agg(list)
id
0 [SubObj(id=0, name='sub0', value='one'), SubOb...
1 [SubObj(id=0, name='sub0', value='one'), SubOb...
Name: obj, dtype: object
maindf = df'name'.droplevel('sub_id').drop_duplicates().join(sub.groupby('id').agg(list))
maindf
name obj
id
0 test0 [SubObj(id=0, name='sub0', value='one'), SubOb...
1 test1 [SubObj(id=0, name='sub0', value='one'), SubOb...
maindf.reset_index().agg(lambda row: MainObj(*row), axis='columns').to_list()
[MainObj(id=0, name='test0', sub_obj=[SubObj(id=0, name='sub0', value='one'), SubObj(id=1, name='sub1', value='two')]), MainObj(id=1, name='test1', sub_obj=[SubObj(id=0, name='sub0', value='one'), SubObj(id=1, name='sub1', value='two')])]

ebdffaop

ebdffaop2#

像这样的小清单怎么样?

result = [MainObj(
    row[0][0], 
    row[1]['name'], 
    SubObj(
        row[0][1],
        row[1]['sub_name'],
        row[1]['value']
    )
) for row in df.iterrows()]

返回

[MainObj(id=0, name='test0', sub_obj=SubObj(id=0, name='sub0', value='one')),
 MainObj(id=0, name='test0', sub_obj=SubObj(id=1, name='sub1', value='two')),
 MainObj(id=1, name='test1', sub_obj=SubObj(id=0, name='sub0', value='one')),
 MainObj(id=1, name='test1', sub_obj=SubObj(id=1, name='sub1', value='two'))]

更新
刚刚意识到你想要sub_obj的列表。我认为这是一个更好的方法:

results = list()
for _, g in df.groupby(level=0):  # Groupby on first index
    results.append(
        MainObj(
            g.index[0][0],  # Get the first index value
            g['name'].iloc[0],
            [SubObj(row[0][1], row[1]['sub_name'], row[1]['value']) for row in g.iterrows()]))  # List comp iterrating over group rows

[MainObj(id=0, name='test0', sub_obj=[SubObj(id=0, name='sub0', value='one'), SubObj(id=1, name='sub1', value='two')]),
 MainObj(id=1, name='test1', sub_obj=[SubObj(id=0, name='sub0', value='one'), SubObj(id=1, name='sub1', value='two')])]

相关问题