使用 MultiIndex 时如何在 Pandas 中使用转换器

Posted

技术标签:

【中文标题】使用 MultiIndex 时如何在 Pandas 中使用转换器【英文标题】:How to use converter in Pandas when using a MultiIndex 【发布时间】:2021-09-09 09:32:18 【问题描述】:

问题

我有一个 Excel 表格,其中第一行是标题,第二行是该列其余部分的测量单位(即纳米、微米)。 Pandas 提供了一个出色的 read_excel 函数,我可以在其中传递转换器字典。字典的键是列名,值是一个 lambda 函数,它将 excel 值转换为我想要的其他值。在这种情况下,我使用的任何度量的基值(纳米到米)。

我似乎无法弄清楚如何让我的转换器字典使用第二个标题行(测量单位行)。如果我只指定我的标题来获取单位行,它可以工作,但我希望将实际标签包含在我的标题中。

这是我的代码

import numpy as np
import pandas as pd
import re
import os
from typing import Dict
from pandas.core.frame import DataFrame

Converters = 
  "GPa": lambda gpa: gpa * 1_000_000_000,
  "nm": lambda nm: nm / 1_000_000_000,
  "microns": lambda microns: microns / 1_000_000 


# Read and load metadata
directory = data_directory + "/" + metadata_directory
filenames = sorted(os.listdir(directory))
for filename in filenames:
  readData = pd.read_excel("./" + directory + "/" + filename, header=[0,1], converters=Converters)
  print(filename, "\n", readData.head(2))

操作系统规格

设备名称 DESKTOP-AE4IMFH 处理器 Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz 1.50 GHz 已安装 RAM 12.0 GB(可用 11.8 GB) 设备 ID 2B55F49B-6877-455D-88C5-D369A23FB40C 产品编号 00325-96685-10579-AAOEM 系统类型 64 位操作系统,基于 x64 的处理器 触控笔和触控 支持 10 个触控点的触控笔和触控

Windows 10 家庭版 版本 20H2 安装于 ‎7/‎23/‎2020 操作系统版本 19042.1052 体验 Windows 功能体验包 120.2212.2020.0

Python 3.9.5 版

我尝试过的

摆脱 MultiIndex 并将标题指定为第 1 行效果很好。但是,我真的希望将列名作为标题的一部分。

一个想法可能是将 DataFrame 转换为 numpy 数组,然后找到与每个 Converter 函数名称匹配的列索引。然后我们可以手动将转换应用于该列索引处的每一行。但是,这感觉很老套,很想找到一个更清洁的解决方案

【问题讨论】:

【参考方案1】:

我不确定我是否完全理解您要执行的操作。尽管如此, 这是一个建议:

在下面,我以 Excel 文件 test.xlsx 的内容为例

col_1  col_2  col_3
    1      2      3
    1      1      1
    2      2      2
    3      3      3

这个

from operator import mul
from functools import partial

units = pd.read_excel('test.xlsx', nrows=1)
converters = 
    col: partial(mul, 1 / units.at[0, col])
    for col in units.columns

df = pd.read_excel('test.xlsx', skiprows=[1], converters=converters)

产生以下数据框df

   col_1  col_2     col_3
0    1.0    0.5  0.333333
1    2.0    1.0  0.666667
2    3.0    1.5  1.000000

此处不包括包含单位的行。如果要包含它,请将最后一行替换为:

df = pd.concat([
         units,
         pd.read_excel('test.xlsx', skiprows=[1], converters=converters)
     ]).reset_index(drop=True)

结果:

   col_1  col_2     col_3
0    1.0    2.0  3.000000
1    1.0    0.5  0.333333
2    2.0    1.0  0.666667
3    3.0    1.5  1.000000

(如果您想知道为什么我没有使用 lambda 来定义转换器:如果您通过变量定义它们,这通常会失败。)

所以,如果你想将它集成到你的代码中,它看起来像:

from operator import mul
from functools import partial

...

for filename in filenames:
    filepath = "./" + directory + "/" + filename
    units = pd.read_excel(filepath, nrows=1)
    converters = 
       col: partial(mul, 1 / units.at[0, col])
       for col in units.columns
    
   readData = pd.read_excel(filepath, skiprows=[1], converters=converters)

编辑:今天重新思考这个问题后,我意识到使用转换器可能不是最好的方法。转换器功能非常基本(简单除法),因此有更好的解决方案可用:

for filename in filenames:
   readData = pd.read_excel("./" + directory + "/" + filename)

   # Version 1: Discarding row with units
   readData = (readData.iloc[1:, :] / readData.iloc[0, :]).reset_index(drop=True)
   # Version 2: Keeping row with units
   readData.iloc[1:, :] /= readData.iloc[0, :]

【讨论】:

以上是关于使用 MultiIndex 时如何在 Pandas 中使用转换器的主要内容,如果未能解决你的问题,请参考以下文章

使用 MultiIndex 时,如何将此 Pandas 列类型保留为日期时间?

合并pandas DataFrames时如何保留列MultiIndex值

pandas - 如何使用 MultiIndex 在 DataFrame 的深层检索最小值索引

如何使用 pandas multiIndex 查询多列

Pandas DataFrame - 如何检索 MultiIndex 级别的特定组合

如何更新 MultiIndex pandas DataFrame 的子集