zoukankan      html  css  js  c++  java
  • Pandas

    转自:https://blog.csdn.net/qq_42711381/article/details/90451301

    由于刚好也遇到这个问题,记录下来

    使用的DataFrame的

    image

    当使用 frame2['year']['two'] = 10000, 即df名[列名][行名]的方式去赋值就会报错, 提示如下

    SettingWithCopyWarning:
    A value is trying to be set on a copy of a slice from a DataFrame

    See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

    进入提示网页, 查找与SettingWithCopyWarning有关部分, 这里简单翻译了一下(渣翻译, 推荐大家去看原文, 在最后几部分里)

    chained indexing
    
    这就是出现警告的原因, 我们在使用pandas中要极力避免出现chained index)

    下面是一个例子解释到底什么是chained indexing

    In [4]: dfmi = pd.DataFrame([list('abcd'), list('efgh'), list('ijkl'), list('mnop')],
           ...:                     columns=pd.MultiIndex.from_product([['one', 'two'], ['first', 'second']]))
           ...:
        
        In [5]: dfmi
        Out[5]:
            one          two
          first second first second
        0     a      b     c      d
        1     e      f     g      h
        2     i      j     k      l
        3     m      n     o      p

    我们通过两种不同的方式去访问同一值

    #第一种方式
            In [6]: dfmi['one']['second']
        Out[6]:
        0    b
        1    f
        2    j
        3    n
        Name: second, dtype: object
        
    #第二种方式
        In [7]: dfmi.loc[:,('one', 'second')]
        Out[7]:
        0    b
        1    f
        2    j
        3    n
        Name: (one, second), dtype: object

    可以看出虽然访问方式不同, 但是返回的结果是相同的. 相同结果, 但其实第二种访问方式应该是我们所推荐使用的, 原因如下

    第一种访问方式

    使用dfmi['one']['second']其实是分为两个独立事件完成的, 一个事情接着一件事情发生:

    第一步 执行dfmi['one']

    第二步 在第一步的基础上执行dfmi_with_one['second'], 相当于在第一步返回Series基础上, 检索索引['second']

    看似是一步到位的访问, 其实在内部调用了两次__getitem__

    第二种方式访问

    fmi.loc[:,('one', 'second')] 相当于将一个嵌套的元组(slice(None), ('one', 'second'))传递给一个__getitem__, 这就使得pandas将其作为一个整体来处理, 第二种方式比第一种方式速度更快

    这里的第一种访问方式就是chained indexing, 接下来解决为什么chained indexing会造成警告.

           #第二种访问方式(推荐方式)
           dfmi.loc[:, ('one', 'second')] = value
            #其实在编译器中是这样操作的
            dfmi.iloc.setitem((slice(None), ('one', 'second')), value)
            
            #但是这一段代码编译器处理就很不同了
            
             #第一种访问方式chained indexing
            dfmi['one']['second'] = value
            #其实在编译器中是这样操作的
            dfmi.__getitem__('one').__setitem__('second', value)

    问题的关键就出在这里的__getitem__上, 因为我们很难预测到这里的__getitem__返回的是一个视图或是一个copy, 因为我们无法确定__setitem))修改的到底是真实的dfmi或是暂时的copy副本, 这就是SettingWithCopy想要警告我们的.

    到此问题就算是解决了, 出现警告的原因在于无法预测到底修改的是视图还是副本.

    注意

    dfmi.loc保证是dfmi本身伴随修改索引行为(这句话有点不太通顺, 大家可以去看看原文, 重点是后面一句), 所以dfmi.loc.__getitem__和dfmi.loc__setitem__方法一定是直接作用在dfmi上的. 当然dfmi.loc.__getitem__(idx)就无法预测到时作用在视图上或是副本上了.

    另一种会出现这种警告的情形, 虽然这里并没有明显的链式索引.

    In [9]: def do_something(df):
           ...:     foo = df[['bar', 'baz']]
           ...:     #对于foo是视图或是副本, 其实我们是无法得知的
           ...:     foo['quux'] = value
           ...:     return foo

    解决警告的方案:

    使用 DafaFrameming.loc[行名, 列名] = 值 的方式去赋值, 而不是使用DataFrame[][]的形式去赋值.

  • 相关阅读:
    帝国 标签模板 使用程序代码 去除html标记 并 截取字符串
    iis6 伪静态 iis配置方法 【图解】
    您来自的链接不存在 帝国CMS
    帝国cms Warning: Cannot modify header information headers already sent by...错误【解决方法】
    .fr域名注册 51元注册.fr域名
    帝国网站管理系统 恢复栏目目录 建立目录不成功!请检查目录权限 Godaddy Windows 主机
    星外虚拟主机管理平台 开通数据库 出现Microsoft OLE DB Provider for SQL Server 错误 '8004' 从字符串向 datetime 转换失败
    ASP.NET 自定义控件学习研究
    CSS层叠样式表之CSS解析机制的优先级
    ASP.NET程序员工作面试网络收藏夹
  • 原文地址:https://www.cnblogs.com/luhouxiang/p/12306822.html
Copyright © 2011-2022 走看看