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)仍会失败。需要先确认这些值是否应该清洗或视为缺失值。
备注:内容仅供参考。
