使用 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 的深层检索最小值索引