在 Pandas 中,.iloc 方法是不是提供副本或视图?
Posted
技术标签:
【中文标题】在 Pandas 中,.iloc 方法是不是提供副本或视图?【英文标题】:In Pandas, does .iloc method give a copy or view?在 Pandas 中,.iloc 方法是否提供副本或视图? 【发布时间】:2018-06-06 22:40:36 【问题描述】:我发现结果有点随机。有时它是一个副本,有时它是一个视图。例如:
df = pd.DataFrame(['name':'Marry', 'age':21,'name':'John','age':24],index=['student1','student2'])
df
age name
student1 21 Marry
student2 24 John
现在,让我试着稍微修改一下。
df2= df.loc['student1']
df2 [0] = 23
df
age name
student1 21 Marry
student2 24 John
如您所见,没有任何改变。 df2 是一个副本。但是,如果我将另一个学生添加到数据框中...
df.loc['student3'] = ['old','Tom']
df
age name
student1 21 Marry
student2 24 John
student3 old Tom
尝试再次更改年龄..
df3=df.loc['student1']
df3[0]=33
df
age name
student1 33 Marry
student2 24 John
student3 old Tom
现在df3突然变成了一个视图。到底是怎么回事?我猜值“旧”是关键?
【问题讨论】:
【参考方案1】:您从一个 DataFrame 开始,它有两列具有两种不同的 dtype:
df.dtypes
Out:
age int64
name object
dtype: object
由于不同的 dtype 存储在不同的 numpy 数组中,因此您有两个不同的块:
df.blocks
Out:
'int64': age
student1 21
student2 24, 'object': name
student1 Marry
student2 John
如果您尝试对该 DataFrame 的第一行进行切片,它必须从每个不同的块中获取一个值,这使得需要创建一个副本。
df2.is_copy
Out[40]: <weakref at 0x7fc4487a9228; to 'DataFrame' at 0x7fc4488f9dd8>
在第二次尝试中,您正在更改数据类型。由于 'old' 不能存储在整数数组中,因此它将 Series 转换为对象 Series。
df.loc['student3'] = ['old','Tom']
df.dtypes
Out:
age object
name object
dtype: object
现在这个 DataFrame 的所有数据都存储在一个块中(和一个 numpy 数组):
df.blocks
Out:
'object': age name
student1 21 Marry
student2 24 John
student3 old Tom
在这一步,可以在numpy数组上对第一行进行切片而不创建副本,所以它返回一个视图。
df3._is_view
Out: True
【讨论】:
从来不知道df.blocks
_is_view
是一个非常好的功能,我不知道这一点。谢谢【参考方案2】:
一般来说,如果数据框有一个 dtype
,您可以获得视图,而 不是原始数据框的情况:
In [4]: df
Out[4]:
age name
student1 21 Marry
student2 24 John
In [5]: df.dtypes
Out[5]:
age int64
name object
dtype: object
但是,当你这样做时:
In [6]: df.loc['student3'] = ['old','Tom']
...:
第一列被强制转换为object
,因为列不能有混合数据类型:
In [7]: df.dtypes
Out[7]:
age object
name object
dtype: object
在这种情况下,底层.values
将始终返回一个具有相同底层缓冲区的数组,并且对该数组的更改将反映在数据帧中:
In [11]: vals = df.values
In [12]: vals
Out[12]:
array([[21, 'Marry'],
[24, 'John'],
['old', 'Tom']], dtype=object)
In [13]: vals[0,0] = 'foo'
In [14]: vals
Out[14]:
array([['foo', 'Marry'],
[24, 'John'],
['old', 'Tom']], dtype=object)
In [15]: df
Out[15]:
age name
student1 foo Marry
student2 24 John
student3 old Tom
另一方面,混合类型,如您的原始数据框:
In [26]: df = pd.DataFrame(['name':'Marry', 'age':21,'name':'John','age':24]
...: ,index=['student1','student2'])
...:
In [27]: vals = df.values
In [28]: vals
Out[28]:
array([[21, 'Marry'],
[24, 'John']], dtype=object)
In [29]: vals[0,0] = 'foo'
In [30]: vals
Out[30]:
array([['foo', 'Marry'],
[24, 'John']], dtype=object)
In [31]: df
Out[31]:
age name
student1 21 Marry
student2 24 John
但是请注意,只有当它可能是一个视图时才会返回一个视图,即如果它是一个正确的切片,否则,无论数据类型如何,都会制作一个副本:
In [39]: df.loc['student3'] = ['old','Tom']
In [40]: df2
Out[40]:
name
student3 Tom
student2 John
In [41]: df2.loc[:] = 'foo'
In [42]: df2
Out[42]:
name
student3 foo
student2 foo
In [43]: df
Out[43]:
age name
student1 21 Marry
student2 24 John
student3 old Tom
【讨论】:
那么这是否意味着如果数据框有多个 dtypes 我总是会得到一个副本? @Qiyu 有多种数据类型是的。 知道了。谢谢!以上是关于在 Pandas 中,.iloc 方法是不是提供副本或视图?的主要内容,如果未能解决你的问题,请参考以下文章
pandas子集选取的三种方法:[].loc[].iloc[]