【问题标题】:Will changes in DataFrame.values always modify the values in the data frame?DataFrame.values 中的更改是否总是会修改数据框中的值?
【发布时间】:2018-06-20 10:56:05
【问题描述】:

在文档上,它说

NDFrame 的 Numpy 表示 -- Source

“NDFrame 的 Numpy 表示”是什么意思?修改这个 numpy 表示会影响我的原始数据框吗?换句话说,.values 会返回副本还是视图

StackOverflow 中有问题的答案隐式建议(依赖)返回视图。例如,在Set values on the diagonal of pandas.DataFrame 接受的答案中,np.fill_diagonal(df.values, 0) 用于将df 的对角线部分的所有值设置为0。即在这种情况下返回一个视图。但是,如@coldspeed's answer 所示,有时会返回一个副本。

这感觉很基础。这对我来说有点奇怪,因为我没有更详细的.values 来源。


除了@coldspeed 的答案中的当前实验之外,另一个返回视图的实验:

df = pd.DataFrame([["A", "B"],["C", "D"]])

df.values[0][0] = 0

我们得到

df
    0   1
0   0   B
1   C   D

虽然现在是混合类型,但我们仍然可以通过设置df.values来修改原来的df

df.values[0][1] = 5
df
    0   1
0   0   5
1   C   D

【问题讨论】:

    标签: python pandas numpy dataframe


    【解决方案1】:

    TL;DR:

    如果返回副本(然后更改值不会改变DataFrame)或values返回视图(然后更改值更改 DataFrame)。不要依赖任何这些情况。如果 pandas 开发人员认为它是有益的,它可能会改变(例如,如果他们改变了 DataFrame 的内部结构)。


    我猜自提出问题以来文档已更改,目前显示为:

    pandas.DataFrame.values

    返回 DataFrame 的 Numpy 表示。

    仅返回 DataFrame 中的值,轴标签将被移除。

    它不再提及NDFrame - 而只是提及“DataFrame 的 NumPy 表示”。 NumPy 表示可以是视图或副本!

    文档还包含一个关于混合数据类型的Note

    注意事项

    dtype 将是较低公分母的 dtype(隐式向上转换);也就是说,如果混合了 dtypes(甚至是数字类型),则将选择容纳所有类型的数据类型。如果您不处理积木,请谨慎使用。

    例如如果 dtype 是 float16 和 float32,则 dtype 将向上转换为 float32。如果 dtype 是 int32 和 uint8,则 dtype 将向上转换为 int32。按照numpy.find_common_type() 约定,混合int64 和uint64 将产生float64 dtype。

    从这些注释中可以明显看出,访问包含不同 dtype 的 DataFrame 的 values 可以(几乎)永远返回视图。仅仅是因为它需要将值放入“最低公分母”dtype 的数组中,并且涉及到副本。

    但是它没有说明视图/复制行为,这是设计使然。 jreback 在 pandas 问题跟踪器 1 中提到这实际上只是一个实现细节:

    这是一个实现细节。由于您获得的是单个 dtyped numpy 数组,因此它被向上转换为兼容的 dtype。如果你有混合 dtypes,那么你几乎总是会有一个副本(例外是混合浮点 dtypes 不会复制我认为),但这是一个 numpy 细节。

    我同意这不是很好,但它从一开始就存在,并且在当前的 pandas 中不会改变。如果导出到 numpy,你需要小心。

    即使Series 的文档也没有提及视图:

    pandas.Series.values

    根据 dtype 以 ndarray 或类似 ndarray 的形式返回 Series

    它甚至提到它甚至可能不会返回一个普通数组,具体取决于 dtype。这当然包括它返回副本的可能性(即使只是假设)。它不保证您能看到。


    .values 何时返回视图,何时返回副本?

    答案很简单:这是一个实现细节,只要是一个实现细节,就不会有任何保证。它是一个实现细节的原因是因为 pandas 开发人员希望确保他们可以根据需要更改内部存储。 但是在某些情况下,创建视图是不可能的。例如,使用包含不同 dtype 列的 DataFrame。

    如果您分析迄今为止的行为,可能会有好处。但只要这是一个实现细节,无论如何你都不应该真正依赖它。

    但是,如果您有兴趣:Pandas 当前在内部存储具有与多维数组相同的 dtype 的列。这样做的好处是您可以非常有效地对行和列进行操作(至少只要它们具有相同的 dtype)。但是如果 DataFrame 包含混合类型,它将有几个内部多维数组。每个 dtype 一个。无法创建指向两个不同数组的视图(至少对于 NumPy),因此当您混合 dtype 时,您将在需要 values 时获得副本。


    旁注,你的例子:

    df = pd.DataFrame([["A", "B"],["C", "D"]])
    
    df.values[0][0] = 0
    

    不是混合数据类型。它有一个特定的 dtype:object。但是object 数组可以包含任何 Python 对象,所以我明白你为什么会说/假设它是混合类型的。


    个人笔记:

    就我个人而言,我更希望values 属性仅在它无法返回视图时才返回视图或错误,以及仅返回副本的附加方法(例如as_array),即使有可能获得看法。这肯定会使行为更可预测,并避免一些意外,例如让属性进行昂贵的复制肯定是出乎意料的。


    1这个问题已经在issue post中提到了,所以文档可能因为这个问题而改变了。

    【讨论】:

      【解决方案2】:

      让我们测试一下。

      首先,使用pd.Series 对象。

      In [750]: s = pd.Series([1, 2, 3])
      
      In [751]: v = s.values
      
      In [752]: v[0] = 10000
      
      In [753]: s
      Out[753]: 
      0    10000
      1        2
      2        3
      dtype: int64
      

      现在,对于 DataFrame 对象。一、考虑非混合dtypes——

      In [780]: df = pd.DataFrame(1 - np.eye(3, dtype=int))
      
      In [781]: df
      Out[781]: 
         0  1  2
      0  0  1  1
      1  1  0  1
      2  1  1  0
      
      In [782]: v = df.values
      
      In [783]: v[0] = 12345
      
      In [784]: df
      Out[784]: 
             0      1      2
      0  12345  12345  12345
      1      1      0      1
      2      1      1      0
      

      进行了修改,这意味着.values 返回了一个视图。

      现在,考虑一个混合 dtypes 的场景 -

      In [755]: df = pd.DataFrame({'A' :[1, 2], 'B' : ['ccc', 'ddd']})
      
      In [756]: df
      Out[756]: 
         A    B
      0  1  ccc
      1  2  ddd
      
      In [757]: v = df.values
      
      In [758]: v[0] = 123
      
      In [759]: v[0, 1] = 'zzxxx'
      
      In [760]: df
      Out[760]: 
         A    B
      0  1  ccc
      1  2  ddd
      

      这里,.values 返回一个副本。


      观察

      .values 对于 Series 返回一个视图,而不管每一行的 dtypes,而对于 DataFrames 这取决于。对于同质 dtype,返回一个视图。否则,复制一份。

      【讨论】:

      • 为什么将值设置为df.values 会改变df?顺便说一句很酷的实验。
      • @Tai 出于效率目的,我相信。返回视图更便宜,这样您就不会复制数据,除非您需要对其进行操作。如果是对象列,那就没办法了,东西需要重新构造。
      • 这是一个很有根据的猜测。但我认为我们不应该对这些实验这么快下结论。
      • 为您的出色实验找到了一个反例!见上文。
      • @cᴏʟᴅsᴘᴇᴇᴅ 据我所知,因为它也可以用单个 numpy 数组表示,所以不能免除,但我不能 100% 确定。
      猜你喜欢
      • 2013-04-19
      • 2021-03-29
      • 1970-01-01
      • 2021-05-30
      • 2019-10-04
      • 1970-01-01
      • 2017-12-09
      • 1970-01-01
      • 2017-06-26
      相关资源
      最近更新 更多