Pandas的这个“毛病”该治治了

Pandas有个“坑”

import pandas as pd

df = pd.DataFrame({
    "A": [1, -1, 2, -2],
    "B": [0, 0, 0, 0]
})

subset = df[df["A"] > 0]
subset["B"] = 1

print(df)

有些版本会输出:

   A  B
0  1  1
1 -1  0
2  2  1
3 -2  0

原始 df 被改了。

但你如果换一种写法、换个 Pandas 版本、或者数据稍微复杂一点,又可能看到:

   A  B
0  1  0
1 -1  0
2  2  0
3 -2  0

df 又没被改。

坑点:这就是问题的核心:同一段代码,结果不稳定。

为什么会这样?

关键在这一行:

subset = df[df["A"] > 0]

在老 Pandas 里:

有时它返回的是 视图(view)

有时返回的是 副本(copy)

且无法通过代码判断是哪一种…

于是当你写:

subset["B"] = 1

就会出现两种情况:

subset 实际是什么
结果
视图
原 df 被一起改
副本
只改 subset,df 不动

这也是为什么 Pandas 会给你一个SettingWithCopyWarning但这个警告本身并不能保证你代码是安全的。

SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.

Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy subset[“B”] = 1

更危险的写法!!

链式写法:

df[df["A"] > 0]["B"] = 1

危险的原因:

df[df["A"] > 0] 可能是视图,也可能是副本

你又立刻在它上面赋值

Pandas自己都不敢保证结果对不对

所以你会看到:

有时生效??

有时完全没效果??

有时只给你一个警告??

那“正确姿势”到底是什么?

只记一句话就够了:

你想改原 df,就在原 df 上改。

栗子🌰:

df.loc[df["A"] > 0, "B"] = 1

这个写法的好处:

没有中间对象

不存在视图 / 副本歧义

Pandas3.0的写时复制(Copy-on-Write)

针对上面的 “坑”,即将发布的Pandas3.0终于选择去 “填”了…

Pandas3.0表示:

只要你不是明确在改原表,就不要偷偷改原表。

也就是说:

你从 DataFrame 派生出来的新对象

在“看起来”就是一个独立副本

对它的修改,不会再悄悄影响原数据!

至于底层是不是复用了内存,那是 Pandas 自己的事,用户不需要操心。

640-12

 

原文链接:https://www.zsiss.com/9793.html,转载请注明出处。
0

评论0

请先
响应式人工智能AI芯片网站模板ZS17579
响应式人工智能AI芯片网站模板ZS17579
3分钟前 有人购买 去瞅瞅看

社交账号快速登录