链接 loc 和 iloc 后更改 pandas 中的值

My *_*ork 5 python dataframe pandas pandas-loc

我有以下问题:在 df 中,我想选择特定的行和特定的列,并在此选择中获取第一个n元素并为其分配新值。天真地,我认为下面的代码应该可以完成这项工作:

import seaborn as sns
import pandas as pd

df = sns.load_dataset('tips')
df.loc[df.day=="Sun", "smoker"].iloc[:4] = "Yes"
Run Code Online (Sandbox Code Playgroud)

loc和都iloc应该返回 df 的视图,并且该值应该被覆盖。但是,数据框不会改变。为什么?

我知道如何解决这个问题 - 首先使用 来创建一个新的 df loc,然后使用更改值iloc并更新回原始 df (如下所示)。

但是a)我认为这不是最佳的,b)我想知道为什么顶级解决方案不起作用。为什么它返回一个副本而不是视图的视图?

替代解决方案:

df = sns.load_dataset('tips')
tmp = df.loc[df.day=="Sun", "smoker"]
tmp.iloc[:4] = "Yes"
df.loc[df.day=="Sun", "smoker"] = tmp
Run Code Online (Sandbox Code Playgroud)

注意:我已经阅读了文档、这篇非常棒的文章和这个问题,但他们没有解释这一点。df.loc[mask,"z]他们关心的是和链式之间的区别df["z"][mask]

Ale*_*sky 4

我相信df.loc[].iloc[]这是一个链式作业案例,pandas 并不保证您最终会得到一个视图。来自文档

对于设置操作是否返回副本或引用可以取决于上下文。这有时称为链式分配,应该避免。

由于您在 中有一个过滤条件loc,pandas 将创建一个新的过滤pd.Series条件,然后对其应用分配。例如,以下内容将起作用,因为您将获得与以下相同的系列df["smoker"]

df.loc[:, "smoker"].iloc[:4] = 'Yes'
Run Code Online (Sandbox Code Playgroud)

但你会收到SettingWithCopyWarning警告。

您需要重写代码,以便 pandas 将其作为单个loc实体处理。

另一种可能的解决方法:

df.loc[df[df.day=="Sun"].index[:4], "smoker"] = 'Yes'
Run Code Online (Sandbox Code Playgroud)