【问题标题】:Pandas: Get SettingWithCopyWarning when using set_categoriesPandas:使用 set_categories 时获取 SettingWithCopyWarning
【发布时间】:2016-10-16 19:14:52
【问题描述】:

我有两个数据框。两者都有相同的列集,但有些列是分类类型的(基于实际包含的值)。为了将它们结合起来,我用两个值的并集刷新了分类列的分类类型。

def appendDFsWithCat(df1, df2):
    columns = df1.select_dtypes(include=['category']).columns
    for c in columns:
        catValues1 = list(df1[c].cat.categories)
        catValues2 = list(df2[c].cat.categories)
        catValues = list(set(catValues1 + catValues2))
        df1[c] = df1[c].cat.set_categories(catValues)
        df2[c] = df2[c].cat.set_categories(catValues)
    return df1.append(df2, ignore_index=True).reset_index(drop=True)

一切正常,但我想了解为什么在执行此代码时会引发 SettingWithCopyWarning:

df1[c] = df1[c].cat.set_categories(catValues)
Utility.py:149: SettingWithCopyWarning:

除了使用过的,我发现没有其他可能刷新类别数据。

【问题讨论】:

  • 你应该包括df1df2的例子

标签: python pandas dataframe categorical-data chained-assignment


【解决方案1】:

这很可能是因为您传递给函数的对象。

如果我设置以下示例:

cats1 = pd.Series(['a', 'a', 'b', 'b'], name='cat', dtype="category")
data1 = pd.Series([1, 2, 3, 4], name='val', dtype=np.int64)
df1 = pd.concat([cats1, data1], axis=1)

并运行你的函数:

print appendDFsWithCat(df1, df1)

我没有收到错误,这个输出:

  cat  val
0   a    1
1   a    2
2   b    3
3   b    4
4   a    1
5   a    2
6   b    3
7   b    4

但是,如果我运行这个:

print appendDFsWithCat(df1.iloc[:-1], df1)

我收到以下警告:

C:\Anaconda2\lib\site-packages\ipykernel\__main__.py:7: 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: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

这个输出:

  cat  val
0   a    1
1   a    2
2   b    3
3   a    1
4   a    2
5   b    3
6   b    4

如果您阅读警告,它会告诉您您正在尝试在一个对象上设置值,该对象是另一个对象的切片或视图。这意味着您在特定位置分配值的数据框只是对另一个对象的引用。我通过将数据帧传递给我知道是切片或视图的函数来制造这种情况。

您可以通过强制对象成为自己的东西来解决这个问题,如下所示:

解决方案


def appendDFsWithCat(df1, df2):
    # I added this line to ensure they are their own dataframes
    df1, df2 = df1.copy(), df2.copy()
    columns = df1.select_dtypes(include=['category']).columns
    for c in columns:
        catValues1 = list(df1[c].cat.categories)
        catValues2 = list(df2[c].cat.categories)
        catValues = list(set(catValues1 + catValues2))
        df1[c] = df1[c].cat.set_categories(catValues)
        df2[c] = df2[c].cat.set_categories(catValues)
    return df1.append(df2, ignore_index=True).reset_index(drop=True)

现在当我跑步时:

print appendDFsWithCat(df1.iloc[:-1], df1)

我明白了:

  cat  val
0   a    1
1   a    2
2   b    3
3   a    1
4   a    2
5   b    3
6   b    4

现在有警告。

【讨论】:

  • 感谢您的长篇回答。是的,我还尝试了复制数据框的解决方案。但我看到了使用双倍内存的大缺点。我使用此函数附加的数据框可能非常大。
猜你喜欢
  • 2018-12-25
  • 2017-07-16
  • 2014-10-18
  • 2018-09-04
  • 2021-11-20
  • 2014-12-30
  • 2017-12-19
相关资源
最近更新 更多