在Pandas中,.iloc方法返回的是副本还是视图?

37

我觉得结果有点随机。有时候是复制,有时候是视图。比如:

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突然变成了一个视图。到底发生了什么?我猜'value'的值是关键字?

2个回答

30

你现在有一个DataFrame,其中包含两列数据,这两列数据的数据类型不同:

df.dtypes
Out: 
age      int64
name    object
dtype: object

由于不同的数据类型在底层存储在不同的numpy数组中,因此您需要为它们准备两个不同的数据块:

df.blocks

Out: 
{'int64':           age
 student1   21
 student2   24, 'object':            name
 student1  Marry
 student2   John}
如果您尝试切片这个数据框的第一行,它必须从每个不同的块获取一个值,这使得创建副本成为必要。
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

1
从来不知道 df.blocks - juanpa.arrivillaga
1
_is_view 是一个非常好的功能,我之前不知道它。谢谢。 - Puneet Tripathi

19

一般来说,如果数据框只有一个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

11
如果数据框中有多个数据类型,那么这是否意味着我总是会得到一份副本? - Qiyu
1
@Qiyu 支持多种数据类型。 - juanpa.arrivillaga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接