Pandas 数据框的多索引列的级别合并错误

问题描述 投票:0回答:2

我有以下带有两行标题的电子表格作为工作簿的一部分。

Name Age Genre Monthly Annually Department        Region
P1   28  Female 1000   12000    I.T.              North
P2   25  Male   1100   13200    I.T.              South
P3   29  Female 1500   18000    Human Ressources  North

目标是获得一个包含所有数据和一级列的数据框,其中我们得到“./Genre”、“Salary/Monthly”、“Salary/Anually”、“./Department”等。即使单元格 D1 和 E1 被合并,Pandas 也会查看 E1,例如 C1 或 F1(空内容)。
基于这篇文章,我采用以下代码解决了部分问题:

import pandas as pd

minimal_df = test_df = pd.read_excel(io="multiIndex_columns.xlsx", sheet_name="sample", header=None, skiprows=2, nrows=3) 

minimal_index = pd.read_excel(io="multiIndex_columns.xlsx", sheet_name="sample", header=None, nrows=2)

如果我们查看

minimal_index
的呈现方式,我们会在第 3 列找到“薪水”,但在第 4 列却找不到。

      0    1      2        3        4           5       6
0   NaN  NaN    NaN   Salary      NaN         NaN     NaN
1  Name  Age  Genre  Monthly  Anually  Department  Region

无论如何,在填充辅助数据框中的 NA 值后,就完成了将列名称分配给数据框的操作。

minimal_index.fillna(method='ffill', axis=1, inplace=True)

minimal_df.columns = pd.MultiIndex.from_arrays(minimal_index.values)

nan/Name nan/Age nan/Genre Salary/Monthly Salary/Annually Salary/Department   Salary/Region
P1       28      Female    1000           12000           I.T.                North
P2       25      Male      1100           13200           I.T.                South
P3       29      Female    1500           18000           Human Ressources    North

上图,我们通过PyCharm Community Edition 2023.1.4查看最终结果。然而,由于

fillna()
使用的“填充”方法,部门和地区列也与薪资相关。另一方面,除了在前三列上保留 NaN 值之外,我什么也不能分配,因为
fillna()
不能同时允许“值”和“方法”参数。

有没有办法同时解决这两部分,避免 Excel 修改文件?基于 Pandas 或其他库的什么解决方案可以识别输入单元格的合并?

python pandas excel dataframe multi-index
2个回答
0
投票

我认为这对熊猫来说是不可能的。我会使用 来处理 merged 单元格:

import openpyxl

ws = openpyxl.load_workbook("file.xlsx")["sample"]

TR, BR = 1, 2 # <-- top and bottom rows holding the header
SR = 3 # <-- the row indice where the table starts (excluding the header)

def get_val(x, sheet=ws):
    if isinstance(x, openpyxl.cell.cell.MergedCell):
        for r in sheet.merged_cells.ranges:
            if r.__contains__(x.coordinate):
                return r.start_cell.value 
    else:
        return x.value if x.value else ""

header = [
    f"{get_val(c1)}/{get_val(c2)}" if get_val(c1) else f"./{c2.value}"
    for (c1,c2) in zip(ws[TR], ws[BR])
]

data = [row for row in ws.iter_rows(min_row=SR, values_only=True)]

df = pd.DataFrame(data, columns=header)

输出(df):

信息/姓名 信息/年龄 信息/类型 ./Id 工资/月薪 薪资/年薪 ./部门 ./地区
P1 28 id001 1000 12000 I.T.
P2 25 id002 1100 13200 I.T.
P3 29 id003 1500 18000 人力资源

使用的输入(file.xlsx):


0
投票

看起来“薪水”最初是跨 2 个合并的 EXCEL 单元格(D1、E1)。

取消合并这些,然后将 D1 复制到 E1,应该会产生如您所期望的

minimal_index

© www.soinside.com 2019 - 2024. All rights reserved.