【问题标题】:SettingWithCopyWarning even when using .loc[row_indexer,col_indexer] = valueSettingWithCopyWarning 即使使用 .loc[row_indexer,col_indexer] = value
【发布时间】:2021-11-30 10:26:55
【问题描述】:

这是我的代码中获得SettingWithCopyWarning 的行之一:

value1['Total Population']=value1['Total Population'].replace(to_replace='*', value=4)

然后我改为:

row_index= value1['Total Population']=='*'
value1.loc[row_index,'Total Population'] = 4

这仍然给出相同的警告。我该如何摆脱它?

另外,对于我使用过的 convert_objects(convert_numeric=True) 函数,我收到了同样的警告,有什么办法可以避免这种情况。

 value1['Total Population'] = value1['Total Population'].astype(str).convert_objects(convert_numeric=True)

这是我收到的警告消息:

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 the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy 

【问题讨论】:

  • 因为您同时更新该数据框中的同一组值,您可以尝试使用临时变量来保存结果并应用回列,看看这是否有助于消除警告信息。
  • 你用的是什么版本的python和pandas?

标签: python pandas


【解决方案1】:

如果您使用.loc[row,column] 仍然出现相同的错误,可能是因为复制了另一个数据框。你必须使用.copy()

这是一步一步的错误重现:

import pandas as pd

d = {'col1': [1, 2, 3, 4], 'col2': [3, 4, 5, 6]}
df = pd.DataFrame(data=d)
df
#   col1    col2
#0  1   3
#1  2   4
#2  3   5
#3  4   6

创建一个新列并更新它的值:

df['new_column'] = None
df.loc[0, 'new_column'] = 100
df
#   col1    col2    new_column
#0  1   3   100
#1  2   4   None
#2  3   5   None
#3  4   6   None

我没有收到任何错误。但是,让我们根据前一个数据框创建另一个数据框:

new_df = df.loc[df.col1>2]
new_df
#col1   col2    new_column
#2  3   5   None
#3  4   6   None

现在,使用.loc,我将尝试以相同的方式替换一些值:

new_df.loc[2, 'new_column'] = 100

但是,我又收到了这个可恶的警告:

试图在 DataFrame 的切片副本上设置一个值。尝试 使用 .loc[row_indexer,col_indexer] = value 代替

请参阅文档中的注意事项: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

解决方案

在创建新数据框时使用.copy() 将解决警告:

new_df_copy = df.loc[df.col1>2].copy()
new_df_copy.loc[2, 'new_column'] = 100

现在,您不会收到任何警告!

如果您的数据框是在另一个数据框之上使用过滤器创建的,请始终使用.copy()

【讨论】:

    【解决方案2】:

    指定它是为我工作的副本。我刚刚在语句末尾添加了.copy()

    value1['Total Population'] = value1['Total Population'].replace(to_replace='*', value=4).copy()
    

    【讨论】:

      【解决方案3】:

      我来到这里是因为我想根据另一列中的值有条件地设置新列的值。

      对我有用的是 numpy.where:

      import numpy as np
      import pandas as pd
      ...
      
      df['Size'] = np.where((df.value > 10), "Greater than 10", df.value)
      

      来自numpy docs,这相当于:

      [xv if c else yv
       for c, xv, yv in zip(condition, x, y)]
      

      这是一个非常好的使用 zip...

      【讨论】:

        【解决方案4】:

        我不知道这对数据存储/内存的影响有多严重,但它每次都会为您的平均数据帧修复它:

        def addCrazyColFunc(df):
            dfNew = df.copy()
            dfNew['newCol'] = 'crazy'
            return dfNew
        

        就像消息中所说的那样...复制一份就可以了。请如果有人可以在没有副本的情况下修复上述问题,请发表评论。上面所有的 loc 东西都不适用于这种情况。

        【讨论】:

          【解决方案5】:

          我能够使用如下语法避免相同的警告消息:

          value1.loc[:, 'Total Population'].replace('*', 4)
          

          请注意,数据框不需要重新分配给自己,即 value1['Total Population']=value1['Total Population']...

          【讨论】:

          • 这对我来说看起来很合理......但在我的情况下不起作用
          【解决方案6】:

          找到解决办法:

          我创建了一个新的 DataFrame 并只存储了我需要处理的列的值,现在它没有给我任何错误!

          奇怪,但有效。

          【讨论】:

            【解决方案7】:

            你试过直接设置吗?:

            value1.loc[value1['Total Population'] == '*', 'Total Population'] = 4
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2022-11-29
              • 2018-10-06
              • 2018-12-22
              • 1970-01-01
              • 2017-11-28
              • 2023-03-11
              • 2014-07-04
              相关资源
              最近更新 更多