Pandas不同数据类型列切片:视图还是副本?相关疑问解析
pandas视图与副本问题解析
原始数据准备
import pandas as pd df = pd.DataFrame([[1,2.0],[3,4.0]], index = ['row1','row2'], columns = ['a','b']) df2 = df.iloc[:, :] df3 = df.iloc[:1, :] df4 = df.iloc[:, :1]
其中列a为int类型,列b为float类型。
问题1:df2、df3、df4是视图还是副本?
测试1结果分析
执行以下代码:
print(df._is_view, df._is_copy) print(df2._is_view, df2._is_copy) print(df3._is_view, df3._is_copy) print(df4._is_view, df4._is_copy)
输出:
False None False None False <weakref at 0x7fed1113de90; to 'DataFrame' at 0x7fed11aa80a0> True <weakref at 0x7fed114d65c0; to 'DataFrame' at 0x7fed11aa9ab0>
要明确两个内部标记的实际含义:
_is_view:标记当前对象是否是原数据的子集视图且直接共享内存。全量切片、连续行切片不会被标记为视图,因此df2、df3的_is_view为False。_is_copy:标记当前对象是否由父对象切片衍生而来,df3、df4都指向原df的弱引用,说明二者都是切片衍生对象。df4的_is_view为True,是因为它是单一不同类型列的切片,pandas将其认定为原列数据的视图。
测试2结果与矛盾解释
执行以下代码:
df2.loc['row1', 'b'] = 100.0 print(df) df3.loc['row1', 'a'] = 1000.0 print(df) df4.loc['row1', 'a'] = 10000.0 print(df)
输出:
a b row1 10 2.0 row2 3 4.0 a b row1 100 2.0 row2 3 4.0 a b row1 100 2.0 row2 3 4.0
同时触发SettingWithCopyWarning警告。
矛盾点的核心原因是:pandas的视图/副本不是绝对判定,而是由内存布局和操作类型共同决定:
df2和df3:全量切片或连续行切片的数据在内存中是连续存储块,修改操作直接作用于原数据内存,因此表现为视图行为(修改同步原df);但_is_view为False是因为内部标记的定义更严格,仅将非连续或特定类型切片视为视图。df4:单一列切片,原df的不同类型列存储在独立内存块中。虽然_is_view标记为视图,但执行修改时,pandas的SettingWithCopy机制会检测到这是切片衍生对象,为避免意外修改原数据,内部自动创建了副本,因此修改的是副本而非原df,原数据不会同步更新。
问题2:SettingWithCopyWarning中的“a copy of a slice”是什么?
- “a slice”指的是通过
df.iloc[:, :1]得到的df4,它是原df的列切片衍生对象。 - “a copy of a slice”指的是执行修改操作时,pandas内部自动创建的
df4的临时副本。你实际修改的是这个副本,而非原df的视图,因此原df数据不会同步变化。 - 这个警告的作用是提醒:当前修改操作可能没有作用到你预期的原数据上,而是修改了临时副本,避免出现意外的数据不一致问题。
内容的提问来源于stack exchange,提问作者doraemon
相关产品推荐
相关产品推荐

