Python 熊猫在现场操作中的应用

Python 熊猫在现场操作中的应用,python,pandas,in-place,Python,Pandas,In Place,我期待着一种奇怪的行为。在下面的代码中 import numpy as np import pandas as pd def info(df): print(f"whole df: {hex(id(df))}") print(f"col a : {hex(id(df['a']))}") print(f"col b : {hex(id(df['b']))}") print(f"col c : {hex(id(df['c']))}") def _dro

我期待着一种奇怪的行为。在下面的代码中

import numpy as np
import pandas as pd

def info(df):
    print(f"whole df: {hex(id(df))}")
    print(f"col a   : {hex(id(df['a']))}")
    print(f"col b   : {hex(id(df['b']))}")
    print(f"col c   : {hex(id(df['c']))}")

def _drop(col):
    print(f"called on  : {col.name}")
    print(f"before drop: {hex(id(col))}")
    col[0] = -1    
    col.dropna(inplace=True)
    col[0] = 1
    print(f"after drop : {hex(id(col))}")   


df = pd.DataFrame([[np.nan, 1.2, np.nan],
                   [5.8, np.nan, np.nan]], columns=['a', 'b', 'c'])

info(df)
df.apply(_drop)
info(df)
如果我注释掉
dropna()
行,或者调用
dropna(inplace=False)
我会得到我预期的结果(因为
dropna
创建了一个副本,我正在修改原始序列):

但是当
dropna(inplace=True)
操作应该在原地完成,从而修改原始序列,但是我得到的结果是:

     a    b    c
 0 -1.0 -1.0 -1.0
 1  5.8  NaN  NaN
不过,我希望结果与以前的情况相同。
dropna
操作是否返回克隆,即使该操作已就位? 我使用的是熊猫版本0.23.1

编辑: 根据提供的答案,我添加了
hex(ids())
调用来验证实际实例。上面的代码对此进行了打印(值可能不同,但它们之间的相等性应该相同)

奇怪的是,该函数在
a
b
列上被调用了2次,但是该函数表示只在第一列上调用了两次

此外,列
b
第二遍的十六进制值不同。当省略
列drop()
时,这两种情况都不会发生


十六进制值表明,<代码> .Apple()>代码>创建了一个新的列副本,但是它如何将这些值传播回原来的<代码> df>代码>我不知道。

我试图用可变范围的概念来解释这一点,不认为它是一个完整的答案,但对其他人来说可能是有洞察力的。p>
当.apply在与col参数对应的每个系列上执行时,在_drop()行col[0]=-1的范围内,全局更改df的“第一行”,因此它会对其进行变异。当使用inplace=True调用dropna()时,实际会删除nan,但仅针对该函数范围内的序列,它不会分配给全局df。即使它覆盖了变量col。另一个洞察可能是Docs说.dropna(inplace=True)返回None,_drop()也将返回None,因为没有return语句

在pandas/numpy github上提出这个问题可能是值得的-对我来说,这看起来像是意外的行为-如果您向函数添加
return col
语句,您的代码将按预期工作。这表明确实创建了本地副本<代码>打印(十六进制(id(col))确认这一点

def _drop(col):
    col[0] = -1
    col.dropna(inplace=True)
    col[0] = 1
    return col # <----

df = pd.DataFrame([[np.nan, 1.2, np.nan],
                   [5.8, np.nan, np.nan]], columns=['a', 'b', 'c'])

df.apply(_drop)
def_下降(col):
列[0]=-1
col.dropna(就地=真)
列[0]=1

return col#你期望你的期望输出是什么?请参考这篇文章了解inplace@J先生:这篇文章并没有回答作者的问题……这是一个有趣的问题——如果你在函数中添加两次
print(hex(id(col))
,你会发现没有复制done@Thomas它讨论了inplace是如何工作的。是的,这种方法是有效的,但是行
df.apply(\u drop)
创建了一个新的数据帧。原始的
df
与我的问题一样保留为-1。这可能就是id不同的原因。如前所述,我建议在上提出一个问题。即使这不是一个bug,也绝对是意外行为。如果你提出了问题,请在这里发布链接,我也对结果感兴趣。行
col[0]=-1
不会全局更改df的第一行,但只更改
col
系列中的第一行(这是df中的一个特定元素)。我更新了我的代码,您可以看到,变量
col
在删除后没有修改。最后,我看不到任何与返回类型的连接,无论是
.dropna(inplace=True)
还是
\u drop()。
whole df   : 0x1f482392f28
col a      : 0x1f482392f60
col b      : 0x1f48452af98
col c      : 0x1f48452ada0
called on  : a
before drop: 0x1f480dcc2e8
after drop : 0x1f480dcc2e8
called on  : b
before drop: 0x1f480dcc2e8
after drop : 0x1f480dcc2e8
called on  : a
before drop: 0x1f480dcc2e8
after drop : 0x1f480dcc2e8
called on  : b
before drop: 0x1f4ffef1ef0
after drop : 0x1f4ffef1ef0
called on  : c
before drop: 0x1f480dcc2e8
after drop : 0x1f480dcc2e8
whole df   : 0x1f482392f28
col a      : 0x1f482392f60
col b      : 0x1f48452af98
col c      : 0x1f48452ada0
def _drop(col):
    col[0] = -1
    col.dropna(inplace=True)
    col[0] = 1
    return col # <----

df = pd.DataFrame([[np.nan, 1.2, np.nan],
                   [5.8, np.nan, np.nan]], columns=['a', 'b', 'c'])

df.apply(_drop)