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