为什么Pandas允许编辑DataFrames而不是Series对象

时间:2017-08-06 19:21:52

标签: python pandas

假设我有一个如下数据集: enter image description here

当我尝试覆盖特定列(Series对象)时,我收到以下代码的错误:

mask = bond["Actor"] == "Sean Connery"
bond[mask]["Actor"] = "Sir Sean Connery"

但是当我向下移动一个级别而不是编辑这些行的所有列(完整的DataFrame)时,我成功了

mask = bond["Actor"] == "Sean Connery"
bond[mask] = "Sir Sean Connery"

为什么会这样?在第一种情况下,我认为编辑副本并因此错误是不合逻辑的。但同样适用于后一种情况,因为第二个示例也应该返回原始DataFrame的副本。

2 个答案:

答案 0 :(得分:0)

您需要loc才能避免chained indexing

bond = pd.DataFrame({'Actor':list('abcaef'),
                   'A':list('efghij'),
                   'B':list('aaabbb')})

print (bond)
   A Actor  B
0  e     a  a
1  f     b  a
2  g     c  a
3  h     a  b
4  i     e  b
5  j     f  b
mask = bond["Actor"] == "a"
bond.loc[mask] = "AAA"
#for select all columns :, for columns can be omitted
#bond.loc[mask,:] = "AAA"

print (bond)
     A Actor    B
0  AAA   AAA  AAA
1    f     b    a
2    g     c    a
3  AAA   AAA  AAA
4    i     e    b
5    j     f    b

#one column Actor
bond.loc[mask, "Actor"] = "AAA"
print (bond)
   A Actor  B
0  e   AAA  a
1  f     b  a
2  g     c  a
3  h   AAA  b
4  i     e  b
5  j     f  b

答案 1 :(得分:0)

考虑以下单列DataFrame:

export class AppComponent {
inboundClick = false;
}

这是你想要用于切片的面具:

df = pd.DataFrame({'Actor': ['Sean Connery', 'Sean Connery', 
                             'Sean Something', 'Sean Something Else']})

df
Out: 
                 Actor
0         Sean Connery
1         Sean Connery
2       Sean Something
3  Sean Something Else

现在,如果我使用mask = df['Actor'] == 'Sean Connery' ,则会执行此操作:

df[mask]['Actor'] = 'Sir Sean Connery'
df.__getitem__(mask).__setitem__('Actor', 'Sir Sean Connery')
     

请参阅文档中的警告:http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

对于这种情况,它不会修改原始DataFrame:

__main__:1: 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

Id 确实修改了一个DataFrame - 这是由df Out: Actor 0 Sean Connery 1 Sean Connery 2 Sean Something 3 Sean Something Else 方法返回的,但由于它没有分配给任何东西,所以它会丢失。

相反,在您的第二个示例(__getitem__)中,执行的代码是:

df[mask] = 'Sir Sean Connery'

由于掩码,您可能认为它也使用df.__setitem__(mask, 'Sir Sean Connery') ,但事实并非如此。它直接使用__getitem__并将掩码传递给该DataFrame。并且pandas确保我们使用__setitem__我们可以确保它将在视图上运行。对于__setitem__的情况,它表示它可以是复制品,也可以是一种观点 - 很难知道。

现在您将看到原始df已被修改:

__getitem__

虽然有一个问题。它起作用,因为我们只有一列。如果我们有另一个专栏,比如说“年”,它会将相应的“年”值设置为“肖恩·康纳利爵士”#39;太。为了避免这种情况,我们使用df Out: Actor 0 Sir Sean Connery 1 Sir Sean Connery 2 Sean Something 3 Sean Something Else 作为jezrael指出。它还调用.loc方法,并允许指定哪些列将更改。

__setitem__

因此,基于掩码和列名设置的最佳做法是使用df = pd.DataFrame({'Actor': ['Sean Connery', 'Sean Connery', 'Sean Something', 'Sean Something Else'], 'Year': [1990, 1990, 1990, 1990]}) df.loc.__setitem__((mask, 'Actor'), 'Sir Sean Connery') df Out: Actor Year 0 Sir Sean Connery 1990 1 Sir Sean Connery 1990 2 Sean Something 1990 3 Sean Something Else 1990

.loc

通过这种方式,如果您正在操作副本,则不必担心。