PAYATHON 2026

Pandas 3 中 astype 转换为何触发 LossySetItemError?

数据小许

结论

报错发生在赋值时:data.iloc[:, i].astype(np.float64) 会返回一个 float64 Series,但写回 data.iloc[:, i] 时,赋值目标仍是原来的 int64 列。小数无法无损存入整数列,因此 Pandas 3 会抛出 LossySetItemError,并显示 Invalid value ... for dtype 'int64'。

按位置使用 DataFrame.isetitem 替换整列后,DataFrame 会接收新列的 float64 dtype。列名为 MultiIndex 时也可以使用这个方法。

替换列并转换类型

import numpy as np
import pandas as pd

data = pd.read_excel("file_name.xlsx", header=[10, 11])

for i in range(1, len(data.columns)):
    converted = data.iloc[:, i].astype(np.float64)
    data.isetitem(i, converted)

这里跳过位置为 0 的时间列,将其余列逐列转换。isetitem(i, converted) 按列位置替换整列,DataFrame 中的 MultiIndex 列标签会保留。

如果还需要归一化,也可以计算后替换整列,避免将小数结果写回原来的整数列。下面的示例按每列的最小值和最大值进行 min-max 归一化:

for i in range(1, len(data.columns)):
    values = data.iloc[:, i].astype(np.float64)
    minimum = values.min()
    maximum = values.max()

    if maximum == minimum:
        # 常数列无法按 max - min 归一化;这里将其置为 0.0
        normalized = pd.Series(0.0, index=values.index)
    else:
        normalized = (values - minimum) / (maximum - minimum)

    data.isetitem(i, normalized)

如果只想将每个值除以该列最大值,可以把计算改为 values / maximum。要先处理最大值为 0 的列,以免除零。仅除以最大值后,只有数据非负且最大值非零等条件成立时,结果才会落在 0 到 1 之间。

为什么 astype 仍然报错

astype 已经完成了 Series 的类型转换,问题出在后续赋值。原代码:

data.iloc[:, i] = data.iloc[:, i].astype(np.float64)

会把新 Series 的值写入已有列。错误信息中的 dtype 'int64' 指的就是赋值目标原来的 dtype。归一化产生的除法结果也是 float64;如果目标列仍是 int64,用相同的 iloc 赋值也可能触发这个问题。需要替换整列,而不只是转换右侧的 Series。

注意事项

  • 示例跳过第一列,前提是它确实是无需处理的时间列。如果时间列位置不同,请相应调整循环范围。
  • 使用 read_excel 的 dtype 参数按列指定类型时,MultiIndex 列标签可能需要与实际列标签匹配。如果不确定标签格式,可以在读入后按位置转换并替换整列。
  • 如果列中有文本或其他无法转换为浮点数的值,astype(np.float64) 仍会失败。需要先确认这些值是否应该清洗或视为缺失值。

备注:内容仅供参考。