pandas 日期 map 后,iloc 写入报 Cannot modify read-only array
日期 Series 映射后再次赋值失败,先区分只读映射结果与父表链式赋值,再用显式数据副本继续编辑。
Series.map() 已经返回新 Series,接着用 iloc 改一个时间,仍然报 ValueError: Cannot modify read-only array。甚至把最后一个值原样赋回去也失败。这时要检查的是映射结果自己的日期数组,不能只按链式赋值处理。
pandas 3.1.0、NumPy 2.5.0、Python 3.14.8 的明确触发组合中,输入是 datetime64[us],映射函数返回 Timestamp。例如下面这种形状:
import pandas as pd
source = pd.Series(pd.date_range("2026-01-01", periods=3, freq="10min"))
mapped = source.map(lambda value: value.replace(year=2067))
# 在受影响路径中,这次写入会失败:
mapped.iloc[-1] = mapped.iloc[-1]
普通整数 Series 能改,不代表日期映射结果也采用相同的存储路径。pandas 3.1.0 的日期数组映射会经过 Index 再取回扩展数组;Index 的不可变存储与随后 Series 的写入行为需要区分。上述故障组合不能扩大为所有 map() 或所有日期 dtype 都会失败。
需要继续修改结果时,明确复制日期数据
映射完成后,用深复制建立后续编辑用的 Series:
mapped = source.map(lambda value: value.replace(year=2067))
editable = mapped.copy(deep=True)
editable.iloc[-1] = editable.iloc[0]
后续把 editable 作为结果使用。mapped 变量仍指向原映射对象;只创建副本却继续修改它,不会避开原路径。深复制保留 Series 的索引和 dtype,不必先转成没有标签的 NumPy 数组,再猜测如何拼回去。
这个办法针对已确认的日期数据。若实际值是 object dtype 中的可变 Python 对象,deep=True 不会递归复制每一个嵌套对象,不能将它等同于标准库 deepcopy()。
不要直接设置底层数组的 writeable 标记。共享存储可能还有不可变对象持有,强行开放写入会越过它们的约定。将 map() 换成 transform() 虽可能改变当前执行路径,也应先确认映射规则、索引和缺失值处理确实等价,不能仅凭这一行不报错就替换业务转换。
与父表没改动是两类问题
若代码是 frame["time"][mask] = value,且父表没更新,应先看链式赋值与 Copy-on-Write。本题直接修改映射后独立变量的 iloc,报错点在只读存储,单纯把语法换成 loc 不会自动复制它。
复查时比较副本修改前后的索引、日期单位、时区和 NaT 位置,并确认原 Series 没有跟着改变。映射函数自身也要覆盖闰日等边界:把 2 月 29 日换到非闰年产生的日期错误,与只读数组无关,应按业务规则决定如何处理,不能被复制步骤掩盖。
这条处理针对 pandas 3.1.0 的上述日期映射路径。保留原锁文件和触发条件,后续升级用同一条日期映射与写入路径复查,确认结果可写、原数据未变后,再决定是否移除这份显式副本。


