DataFrame.values中的更改是否总是会修改数据框中的值?

时间:2018-01-11 07:07:22

标签: python pandas numpy dataframe

在文档上,它说

  

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来修改原始df.values

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

2 个答案:

答案 0 :(得分:9)

TL; DR:

如果返回副本(然后更改值不会更改DataFrame)或values返回视图,则是实现细节(然后更改值更改为DataFrame)。不要依赖这些情况中的任何一个。如果熊猫开发人员认为这将是有益的,那么它可能会改变(例如,如果他们改变了DataFrame的内部结构)。


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

  

pandas.DataFrame.values

     

返回DataFrame的Numpy表示形式。

     

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

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

文档中还包含有关混合dtypes的Note

  

注释

     

dtype将是一个较低的公分母dtype(隐式向上转换);也就是说,如果dtypes(甚至是数字类型)混合在一起,则将选择容纳所有类型的dtypes。如果您不处理这些块,请小心使用。

     

例如如果dtype是float16和float32,则dtype将被向上转换为float32。如果dtype是int32和uint8,则dtype将被转换为int32。根据{{​​1}}的约定,将int64和uint64混合使用会产生float64 dtype。

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

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

  

这是一个实现细节。由于您将获得一个dtyped numpy数组,因此将其转换为兼容的dtype。如果您有混合dtype,则几乎总是会有一个副本(例外是混合浮动dtypes不会复制),但这是一个小细节。

     

我同意这不是很好,但是它从一开始就存在,并且不会在当前的大熊猫中改变。如果要导出到numpy,则需要保重。

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

  

Series

     

取决于dtype,返回系列为ndarray或类似ndarray

它甚至提到根据d​​type可能甚至不返回纯数组。这当然包括它返回副本的可能性(即使只是假设)。它不能保证您得到视图。


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

答案很简单:这是实现细节,只要是实现细节,就没有任何保证。它是实现细节的原因是,熊猫开发人员希望确定是否可以更改内部存储。 但是,在某些情况下,无法创建视图。例如,对于包含不同dtype列的DataFrame。

如果您分析迄今为止的行为,可能会有好处。但是,只要这是实现细节,您就不应该真的依赖它。

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


旁注,例如:

values

不是混合dtype。它具有特定的dtype:df = pd.DataFrame([["A", "B"],["C", "D"]]) df.values[0][0] = 0 。但是object数组可以包含任何Python对象,因此我可以理解为什么您会说/假设它是混合类型。


个人笔记:

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


1 这个问题已在问题发布中提到,因此文档可能因为这个问题而发生了变化。

答案 1 :(得分:7)

让我们测试一下。

首先,使用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会返回副本。

<强>观察

对于Series,

.values会返回一个视图,而不管每行的dtypes,而对于DataFrames,这取决于。对于同质dtypes,返回视图。否则,副本。