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

z18hc3ub  于 2022-12-24  发布在  其他
关注(0)|答案(2)|浏览(148)

问题
我有一个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处理器英特尔(R)核心(TM)i7 - 1065G7 CPU@1.30千兆赫1.50千兆赫安装内存12.0 GB设备ID 2B55F49B-6877 - 455D-88C5-D369A23FB40C产品ID 00325 - 96685 - 10579-AAOEM系统类型64位操作系统,基于x64的处理器笔和触摸笔和触摸支持10个触摸点
版本Windows 10家庭版20H2安装日期2020年7月23日操作系统内部版本19042. 1052体验Windows功能体验包120. 2212. 2020. 0

    • Python版本3.9.5**

我所尝试的

去掉多索引,只将标题指定为第1行效果很好,但是,我确实希望将列名作为标题的一部分。
一种想法是将DataFrame转换为numpy数组,然后找到与每个Converter函数名匹配的列索引,然后手动将转换应用于该列索引处的每一行。但是,这感觉有点笨拙,希望找到一个更干净的解决方案

yhxst69z

yhxst69z1#

我不确定我是否完全理解你想做什么。不过,我有个建议:
下面我将使用一个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)

生成以下 Dataframe 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

(If你可能想知道为什么我没有使用lambdas来定义转换器:如果通过变量定义它们,这通常会失败。)
因此,如果您想将其集成到您的代码中,则如下所示:

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)
    • EDIT**:今天重新思考这个问题后,我意识到使用转换器可能不是最好的方法。转换器函数非常基本(简单除法),因此有更好的解决方案:
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, :]
3okqufwl

3okqufwl2#

我刚刚遇到这个问题,因为我也遇到了同样的问题。虽然@Timus的答案实际上解决了手头的问题,但我想我还是会分享我提出的解决方案,因为它实际上使用了read_excelconverters参数用于多索引 Dataframe 。
假设我们有以下表格(excel格式):

width | height |
   nm |     mm |
----------------
    1 |      4 |
    2 |      5 |
    3 |      6 |

第一行是测量的东西,第二行说明单位。后面所有的行都是测量的数据。
现在,要将excel文件读入Pandas DataFrame并将测量数据转换为米,您可以执行以下操作:

import pandas as pd

converters = {
    ("width", "nm"): lambda nm: nm / 1_000_000_000,
    ("height", "mm"): lambda mm: mm / 1_000,
}

data = pd.read_excel("PATH/TO/EXCEL/FILE", header=[0, 1], converters=converters)
print(data)

这里的关键点是元组用于寻址应用转换器的列(例如("width", "nm"))。
结果如下所示:

width height
             nm     mm
0  1.000000e-09  0.004
1  2.000000e-09  0.005
2  3.000000e-09  0.006

当然,DataFrame中的 * units * 不再正确。要删除它们,可以在脚本中添加以下行:

data.columns = data.columns.droplevel(1)

然后print输出:

width  height
0  1.000000e-09   0.004
1  2.000000e-09   0.005
2  3.000000e-09   0.006

相关问题