Pandas 可以将 Excel 组结构读入 Multiindex 吗?

Posted

技术标签:

【中文标题】Pandas 可以将 Excel 组结构读入 Multiindex 吗?【英文标题】:Can Pandas Read Excel's Group Structure into a MultIndex? 【发布时间】:2018-09-24 08:17:03 【问题描述】:

我有一个 Excel 文件,其中包含一些(大部分)很好地分组的行。我在下面构建了一个假示例。

有没有办法让 Pandas 中的 read_excel 生成保留此结构的多索引?

对于此示例,MultiIndex 将具有四个级别(家庭、个人、儿童(可选)、投资)。如果小计值丢失了,那很好,因为它们可以很容易地在 Pandas 中重新创建。

【问题讨论】:

你能举个具体的例子吗?在这种情况下,屏幕截图很有用。例如,包含一张带有分组的小表格的图像,以及您期望 pandas 数据框的样子。 对于这个例子,我会说:不,不是read_excel。 Pandas 对您在 Excel 中指定的“分组”没有任何意义。 (即通过数据 > 组。) 这是我的想法,但如果存在的话,它会让我的生活更轻松。 【参考方案1】:

不,pandas 无法读取这样的结构。

另一种解决方案是使用 pandas 读取您的数据,但将其转换为易于访问的字典,而不是将您的数据保存在带有 MultiIndex 的数据框中。

有两个合理的要求可以让您的数据更有用:

    让您的投资基金名称独一无二。这是微不足道的。 将您的 Excel 分组转换为指示行的父级的附加列。

在下面的示例中,假设了这 2 个要求。

设置

from collections import defaultdict
from functools import reduce
import operator
import pandas as pd

df = pd.DataFrame('name': ['Simpson Family', 'Marge Simpson', 'Maggies College Fund',
                            'MCF Investment 2', 'MS Investment 1', 'MS Investment 2', 'MS Investment 3',
                            'Homer Simpson', 'HS Investment 1', 'HS Investment 3', 'HS Investment 2',
                            'Griffin Family', 'Lois Griffin', 'LG Investment 2', 'LG Investment 3',
                            'Brian Giffin', 'BG Investment 3'],
                   'Value': [600, 450, 100, 100, 100, 200, 50, 150, 100, 50, 0, 200, 150, 100, 50, 50, 50],
                   'parent': ['Families', 'Simpson Family', 'Marge Simpson', 'Maggies College Fund',
                              'Marge Simpson', 'Marge Simpson', 'Marge Simpson', 'Simpson Family',
                              'Homer Simpson', 'Homer Simpson', 'Homer Simpson', 'Families',
                              'Griffin Family', 'Lois Griffin', 'Lois Griffin', 'Griffin Family',
                              'Brian Giffin'])

    Value                  name                parent  
0     600        Simpson Family              Families   
1     450         Marge Simpson        Simpson Family   
2     100  Maggies College Fund         Marge Simpson   
3     100      MCF Investment 2  Maggies College Fund   
4     100       MS Investment 1         Marge Simpson   
5     200       MS Investment 2         Marge Simpson   
6      50       MS Investment 3         Marge Simpson   
7     150         Homer Simpson        Simpson Family   
8     100       HS Investment 1         Homer Simpson   
9      50       HS Investment 3         Homer Simpson   
10      0       HS Investment 2         Homer Simpson   
11    200        Griffin Family              Families   
12    150          Lois Griffin        Griffin Family   
13    100       LG Investment 2          Lois Griffin   
14     50       LG Investment 3          Lois Griffin   
15     50          Brian Giffin        Griffin Family   
16     50       BG Investment 3          Brian Giffin

第 1 步

定义一个子 -> 父字典和一些实用函数:

child_parent_dict = df.set_index('name')['parent'].to_dict()

tree = lambda: defaultdict(tree)

d = tree()

def get_all_parents(child):

    """Get all parents from hierarchy structure"""

    while child != 'Families':
        child = child_parent_dict[child]
        if child != 'Families':
            yield child

def getFromDict(dataDict, mapList):

    """Iterate nested dictionary"""

    return reduce(operator.getitem, mapList, dataDict)

def default_to_regular_dict(d):

    """Convert nested defaultdict to regular dict of dicts."""

    if isinstance(d, defaultdict):
        d = k: default_to_regular_dict(v) for k, v in d.items()
    return d

第 2 步

将此应用于您的数据框。用它来创建一个嵌套的字典结构,这对于重复查询会更有效。

df['structure'] = df['name'].apply(lambda x: ['Families'] + list(get_all_parents(x))[::-1])

for idx, row in df.iterrows():
    getFromDict(d, row['structure'])[row['name']]['Value'] = row['Value']

res = default_to_regular_dict(d)

结果

数据框

    Value                  name                parent  \
0     600        Simpson Family              Families   
1     450         Marge Simpson        Simpson Family   
2     100  Maggies College Fund         Marge Simpson   
3     100      MCF Investment 2  Maggies College Fund   
4     100       MS Investment 1         Marge Simpson   
5     200       MS Investment 2         Marge Simpson   
6      50       MS Investment 3         Marge Simpson   
7     150         Homer Simpson        Simpson Family   
8     100       HS Investment 1         Homer Simpson   
9      50       HS Investment 3         Homer Simpson   
10      0       HS Investment 2         Homer Simpson   
11    200        Griffin Family              Families   
12    150          Lois Griffin        Griffin Family   
13    100       LG Investment 2          Lois Griffin   
14     50       LG Investment 3          Lois Griffin   
15     50          Brian Giffin        Griffin Family   
16     50       BG Investment 3          Brian Giffin   

                                            structure  
0                                          [Families]  
1                          [Families, Simpson Family]  
2           [Families, Simpson Family, Marge Simpson]  
3   [Families, Simpson Family, Marge Simpson, Magg...  
4           [Families, Simpson Family, Marge Simpson]  
5           [Families, Simpson Family, Marge Simpson]  
6           [Families, Simpson Family, Marge Simpson]  
7                          [Families, Simpson Family]  
8           [Families, Simpson Family, Homer Simpson]  
9           [Families, Simpson Family, Homer Simpson]  
10          [Families, Simpson Family, Homer Simpson]  
11                                         [Families]  
12                         [Families, Griffin Family]  
13           [Families, Griffin Family, Lois Griffin]  
14           [Families, Griffin Family, Lois Griffin]  
15                         [Families, Griffin Family]  
16           [Families, Griffin Family, Brian Giffin]

字典

'Families': 'Griffin Family': 'Brian Giffin': 'BG Investment 3': 'Value': 50,
                                                  'Value': 50,
                                 'Lois Griffin': 'LG Investment 2': 'Value': 100, 'LG Investment 3': 'Value': 50,
                                                  'Value': 150,
                                 'Value': 200,
              'Simpson Family': 'Homer Simpson': 'HS Investment 1': 'Value': 100, 'HS Investment 2': 'Value': 0, 'HS Investment 3': 'Value': 50,
                                                   'Value': 150,
                                 'Marge Simpson': 'MS Investment 1': 'Value': 100, 'MS Investment 2': 'Value': 200, 'MS Investment 3': 'Value': 50,
                                                   'Maggies College Fund': 'MCF Investment 2': 'Value': 100,
                                                                            'Value': 100,
                                                   'Value': 450,
              'Value': 600

【讨论】:

是的,我最终需要以类似的方式在附加列中自己定义它。幸运的是,我不必手动执行此操作,因为文件相当大。我使用这些值“回滚”并确定父结构(即“投资 2”必须是 MCF 的一部分,但“投资 1”必须是 MS 而不是 MCF 的一部分,因为 MCF 总共有 100 个而不是 200 个)。为了做到这一点,我需要在另一个文件中列出“投资”。【参考方案2】:

我认为使用 read_excel as-it 来实现这一点是不可能的。

您可以根据四个层次结构级别(家庭、个人、儿童(可选)、投资)向您的 Excel 工作表添加其他列,然后使用 read_excel()index_col[0,1,2,3] 生成 pandas 数据框。

【讨论】:

是的,不幸的是,实际文档是由外部源生成的大约 10000 行。我目前正在尝试通过利用 value 列来找出一种方法来退出组结构。【参考方案3】:

查看read_excel函数的index_col参数。

https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_excel.html

index_col : int,整数列表,默认无

列(0-indexed)用作DataFrame的行标签。如果没有这样的列,则通过 None。如果传递了一个列表,这些列将被组合成一个 MultiIndex。如果使用 usecols 选择了数据子集,则 index_col 基于该子集。

【讨论】:

感谢 Max,但问题是索引分组不在我的数据源的多个列中。我扩展了示例以使这一点更清楚。

以上是关于Pandas 可以将 Excel 组结构读入 Multiindex 吗?的主要内容,如果未能解决你的问题,请参考以下文章

将excel电子表格读入pandas DataFrame时将数字转换为字符串

如何将带有 NaN 的合并 Excel 单元格读入 Pandas DataFrame

将 S3 中的 excel 文件读入 Pandas DataFrame

只将包含某个单词的 Excel sheet_names 读入 pandas 数据框

将数据分组到 Pandas 多索引

熊猫:将特定的 Excel 单元格值读入变量