始终建议使用SettingWithCopy警告:
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**
因此,我开始使用
df.loc[:,'col'] = arr
来重新分配列,而不是 df['col'] = arr
。
但是,由于在 pandas 1.5.0 中实现了使用 .loc 和 .iloc 设置时的 changes 到就地操作,因此我使用 df.loc[:,'col'] = new_arr
的行为不一致,其中代码将在没有任何警告或错误的情况下执行,但列尝试将列转换为不同的数据类型时,类型未按预期修改。
例如,我有一个数据框weather_df,它在“year”列中读取数据类型为“float64”的数据(缺少默认为NaN的值)。
import pandas as pd
weather_df = pd.read_csv(weather_file)
我想用 0 填充缺失值,并将列 dtype 转换为“int32”。
以下代码静默执行,并将 NaN 值替换为 0,但不修改 pandas 1.5+ 的类型(weather_df['year].dtype 仍为 float64):
weather_df.loc[:,'year'] = weather_df['year'].fillna(0).astype('int32')
令人沮丧的是,以下代码确实修改了pandas 1.5+中的weather_df和'year'列值的数据类型,尽管以前不推荐这样做:
weather_df['year'] = weather_df['year'].fillna(0).astype('int32')
在最近的更改(1.4-)之前,这两行都会更新weather_df,我从文档中了解到,这两行应该继续工作,因为我正在设置整个列。它应该首先尝试就地操作,然后在就地操作因类型不匹配而失败时回退到转换(仅因为我要替换整个列),但 .loc[:,' 不会发生这种情况科尔']。
这是从现在开始的预期行为,还是一个错误?是否有解决方法可以使用 .loc 并获得旧的行为,或者我应该忘记有关使用 .loc 以避免链式分配的旧设置WithCopy 建议?
编辑:我使用 Python 版本 3.8.3 在 Linux x86_64 上运行此程序,并且任何版本 1.5.0 到 2.0.3(最新)都会出现错误。我还澄清了 fillna 似乎在这两种情况下都有效,但使用 .loc 时类型转换不起作用。
以下简化示例为我重现了该问题:
>>> df = pd.DataFrame({'col1':[20.,19.5,21.,24.,23.,22.], 'col2':[2020.,2021.,2022.,2023.,np.nan,2019.]})
>>> print(df['col2'].dtype)
float64
>>> df.loc[:,'col2'] = df['col2'].fillna(0).astype('int32')
>>> print(df['col2'].dtype)
float64
>>> df['col2'] = df['col2'].fillna(0).astype('int32')
>>> print(df['col2'].dtype)
int32
在 astype() 下的 docs 中有一个关于此的微妙注释:
当尝试使用以下方法将列的子集转换为指定类型时 astype() 和 loc(),会发生向上转换。
loc() 尝试适应我们分配给当前数据类型的内容, 而 [] 将从右侧获取 dtype 来覆盖它们 侧面。
旧版本的 pandas 也出现了同样的问题(请参阅关于 pandas 0.18 的这篇文章)。在某些时候(我无法确定何时),这被更改为 df.loc[:,'col'] 和 df['col'] 在使用 .astype() 转换列时产生相同的结果到一个新的类型。我知道这一点是因为 pandas 版本 1.2-1.4(至少)产生了我预期的结果,其中 df['col'].dtype 已更新,无论 df.loc[:,'col'] 或 df['col'] 是否已更新用在作业的左侧。
但是,在 pandas 版本 1.5-2.0.3(Windows/Linux、Python 3.8)中,这种情况再次发生了变化,loc() 和 astype() 交互遵循文档中的微妙注释(请参阅this post 关于 pandas 2.0) .0).
我觉得这种行为应该发出警告,通知用户使用 .loc[] 进行的预期类型转换失败。我将在 pandas-dev GitHub 上提出问题并用链接更新此答案。