python 为什么我在使用多索引时会收到SettingWithCopyWarning(而不是简单索引)?

nxowjjhe  于 2023-01-24  发布在  Python
关注(0)|答案(2)|浏览(110)

下面的代码按预期工作,没有警告。我创建一个 Dataframe ,使用.loc从它创建两个子 Dataframe ,给予它们相同的索引,然后分配给其中一个的列。

import numpy as np
import pandas as pd

df = pd.DataFrame(np.random.randn(20, 4),
                  index=pd.Index(range(20)),
                  columns=['one', 'two', 'three', 'four'])

d1 = df.loc[[2, 4, 6], :]
d2 = df.loc[[3, 5, 7], :]

idx = pd.Index(list('abc'), name='foo')
d1.index = idx
d2.index = idx

d1['one'] = d1['one'] - d2['two']

然而,如果我做完全相同的事情,除了多索引 Dataframe ,我得到一个SettingWithCopyWarning

import numpy as np
import pandas as pd

arrays = [
    np.array(["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"]),
    np.array(["one", "two", "one", "two", "one", "two", "one", "two"]),
]
df = pd.DataFrame(np.random.randn(8, 4), index=arrays, columns=['one', 'two', 'three', 'four'])

d1 = df.loc[(['bar', 'qux', 'foo'], 'one'), :]
d2 = df.loc[(['bar', 'qux', 'foo'], 'two'), :]

idx = pd.Index(list('abc'), name='foo')
d1.index = idx
d2.index = idx

d1['one'] = d1['one'] - d2['two']

我知道在创建df1df2时使用.copy()可以避免这个警告,但是我很难理解为什么在第二种情况下有必要使用.copy(),而在第一种情况下却不需要。链式索引在两种情况下都存在,不是吗?那么,有什么区别呢?

e3bfsja2

e3bfsja21#

您必须使用set_index来避免警告:

import numpy as np
import pandas as pd

arrays = [
    np.array(["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"]),
    np.array(["one", "two", "one", "two", "one", "two", "one", "two"]),
]
df = pd.DataFrame(np.random.randn(8, 4), index=arrays, columns=['one', 'two', 'three', 'four'])

d1 = df.loc[(['bar', 'qux', 'foo'], 'one'), :]
d2 = df.loc[(['bar', 'qux', 'foo'], 'two'), :]

idx = pd.Index(list('abc'), name='foo')
d1 = d1.set_index(idx)  # <- HERE
d2 = d2.set_index(idx)  # <- HERE

d1['one'] = d1['one'] - d2['two']
pobjuy32

pobjuy322#

我相信这福尔斯Pandas的内部,归还副本的决定取决于几个因素(dtype同质性,
您可以使用_is_copy检查是否有副本或视图,并在需要时强制执行:

def ensure_copy(df):
    if df._is_copy:
        return df.copy()
    return df

d1 = ensure_copy(df.loc[(['bar', 'qux', 'foo'], 'one'), :])
d2 = ensure_copy(df.loc[(['bar', 'qux', 'foo'], 'two'), :])

idx = pd.Index(list('abc'), name='foo')
d1.index = idx
d2.index = idx

d1['one'] = d1['one'] - d2['two']
  • 请注意,这是一个内部的panda方法,而不是一个公共的方法,因此不能保证它在未来仍然可用。*

相关问题