Jupyter Notebook运行正确代码单元格卡In[*]无法完成如何解决
问题原因
代码持续处于运行状态的核心诱因是Pandas版本差异带来的行为变化,叠加循环写法本身的性能缺陷:
- 课程讲师使用的大概率是1.x版本的Pandas,该版本下
iteritems()遍历过程中通过loc逐点赋值是直接在原Series对象上修改,虽然写法低效但10000条数据的循环可以在数百毫秒跑完。 - 你本地环境安装的应该是Pandas 2.0以上版本,从该版本开始Pandas逐步默认开启写时复制(Copy-on-Write, CoW)机制:遍历返回的是值的拷贝而非原对象视图,每次通过
loc单标签赋值都会触发整个Series的内存拷贝重分配,时间复杂度直接从O(n)退化为O(n²)。加上%%timeit -n 10会重复执行代码10轮统计平均耗时,整体运行时间会拉长到十几分钟甚至更久,看起来就像永远执行不完。
排查步骤
- 新开单元格执行
import pandas as pd; print(pd.__version__)确认本地Pandas版本,若版本号≥2.0即可初步确认问题来源 - 移除单元格开头的
%%timeit魔法命令,单独执行后续的Series创建+循环代码,观察运行耗时:如果单轮循环耗时就达到数秒到数十秒级别,即可坐实是版本机制带来的性能退化 - 执行
print(pd.get_option("mode.copy_on_write")),如果返回True说明当前环境已开启写时复制机制,和旧版本行为不一致
解决方案
推荐方案(符合Pandas最佳实践)
逐行遍历赋值本身就是Pandas官方明确不推荐的反模式,不管哪个版本性能都远差于向量化操作,直接替换为向量化写法即可,耗时仅需微秒级,全版本Pandas通用:
%%timeit -n 10 # 创建待处理Series s = pd.Series(np.random.randint(0,1000,10000)) # 向量化操作替代循环 s += 2
复现课程演示结果方案
如果你需要严格复现讲师的代码运行效果(保留循环写法),可以在代码块内临时关闭写时复制机制,注意%%timeit必须放在单元格第一行:
%%timeit -n 10 import pandas as pd # 临时关闭CoW,对齐1.x版本行为 pd.set_option("mode.copy_on_write", False) s = pd.Series(np.random.randint(0,1000,10000)) for label, value in s.iteritems(): s.loc[label]= value+2
不推荐通过降级Pandas到1.x版本解决问题,旧版本缺少后续的性能优化、bug修复和新特性。
补充说明
你看到的In[*]状态不是代码死锁,只是运行时间过长。如果不做任何修改硬等代码跑完,在开启CoW的Pandas 2.2+版本上,这段代码总耗时可能超过20分钟。
内容的提问来源于stack exchange,提问作者uditig
相关产品推荐
相关产品推荐

