据我了解,通过切片进行的复制会复制结构的较高级别,但不会复制较低的结构(我不确定何时)。
但是,在这种情况下,我通过切片来制作副本,并且在编辑副本的两列时,原始文档的一列被更改,而另一列则没有更改。
怎么可能?为什么是一列,而不是全部或都不选?
代码如下:
import pandas as pd
import numpy as np
url = 'https://raw.githubusercontent.com/udacity/deep-learning-v2-pytorch/master/intro-neural-networks/student-admissions/student_data.csv'
data = pd.read_csv(url)
# Copy data
processed_data = data[:]
print(data[:10])
# Edit copy
processed_data['gre'] = processed_data['gre']/800.0
processed_data['gpa'] = processed_data['gpa']/4.0
# gpa column has changed
print(data[:10])
另一方面,如果我将processed_data = data[:]
更改为processed_data = data.copy()
,则效果很好。
此处,原始数据已编辑:
答案 0 :(得分:1)
据我了解,通过切片进行的复制会复制结构的上层而不是下层。
这对Python列表有效。切片会创建浅拷贝。
In [44]: lst = [[1, 2], 3, 4]
In [45]: lst2 = lst[:]
In [46]: lst2[1] = 100
In [47]: lst # unchanged
Out[47]: [[1, 2], 3, 4]
In [48]: lst2[0].append(3)
In [49]: lst # changed
Out[49]: [[1, 2, 3], 3, 4]
但是,对于numpy / pandas并非如此。在切片数组时,numpy通常会返回视图。
In [50]: arr = np.array([1, 2, 3])
In [51]: arr2 = arr[:]
In [52]: arr2[0] = 100
In [53]: arr
Out[53]: array([100, 2, 3])
如果您的DataFrame具有单个dtype,则您看到的行为是相同的:
In [62]: df = pd.DataFrame([[1, 2, 3], [4, 5, 6]])
In [63]: df
Out[63]:
0 1 2
0 1 2 3
1 4 5 6
In [64]: df2 = df[:]
In [65]: df2.iloc[0, 0] = 100
In [66]: df
Out[66]:
0 1 2
0 100 2 3
1 4 5 6
但是当您混合使用dtypes时,行为是不可预测的,这是臭名昭著的SettingWithCopyWarning的主要来源:
dfmi['one']['second'] = value # becomes dfmi.__getitem__('one').__setitem__('second', value)
看到那里的
__getitem__
吗?除了简单的案例,这很难 预测是否返回视图或副本(取决于 数组的内存布局,有关熊猫对此不做任何保证), 因此__setitem__
会修改dfmi还是临时 此后立即被抛出的对象。那就是 SettingWithCopy正在警告您!
就您而言,我的猜测是这是熊猫处理不同dtypes的结果。每个dtype都有其自己的块,对于gpa
列,该块本身就是该列。 gre
并非如此-您还有其他整数列。当我将字符串列添加到data
并在processed_data
中对其进行修改时,我会看到相同的行为。当我在data
中将浮点数增加到2时,在gre
中更改processed_data
不再影响原始的data
。
.copy()
;如果要修改DataFrame的某些部分,则不应将这些部分分配给其他变量。您应该使用.loc
或.iloc
直接修改它们。