NumPy 副本和视图
副本是一个数据的完整的拷贝,如果我们对副本进行修改,它不会影响到原始数据,物理内存不在同一位置。
视图是数据的一个别称或引用,通过该别称或引用亦便可访问、操作原有数据,但原有数据不会产生拷贝。如果我们对视图进行修改,它会影响到原始数据,物理内存在同一位置。
视图一般发生在:
- 1、numpy 的切片操作返回原数据的视图。
- 2、调用 ndarray 的 view() 函数产生一个视图。
副本一般发生在:
- Python 序列的切片操作,调用deepCopy()函数。
- 调用 ndarray 的 copy() 函数产生一个副本。
无复制
简单的赋值不会创建数组对象的副本。 相反,它使用原始数组的相同id()来访问它。 id()返回 Python 对象的通用标识符,类似于 C 中的指针。
此外,一个数组的任何变化都反映在另一个数组上。 例如,一个数组的形状改变也会改变另一个数组的形状
>>> import numpy as np
>>> a = np.arange(6)
>>> a
array([0, 1, 2, 3, 4, 5])
>>> id(a)
210103936
>>> b = a
>>> b
array([0, 1, 2, 3, 4, 5])
>>> id(b)
210103936
>>> b.shape = 3,2
>>> b
array([[0, 1],
[2, 3],
[4, 5]])
>>> a
array([[0, 1],
[2, 3],
[4, 5]])
视图或浅拷贝
ndarray.view() 方会创建一个新的数组对象,该方法创建的新数组的维数更改不会更改原始数据的维数
>>> a = np.arange(6).reshape(2,3)
>>> print(a)
[[0 1 2]
[3 4 5]]
>>> b = a.view()
>>> print(b)
[[0 1 2]
[3 4 5]]
>>> id(a)
209561264
>>> id(b)
210104096
>>> b.shape = 3,2
>>> print(b)
[[0 1]
[2 3]
[4 5]]
>>> print(a)
[[0 1 2]
[3 4 5]]
使用切片创建视图修改数据会影响到原始数组:
>>> arr = np.arange(12)
>>> print (arr)
[ 0 1 2 3 4 5 6 7 8 9 10 11]
>>> a=arr[3:]
>>> b=arr[3:]
>>> print(a)
[ 3 4 5 6 7 8 9 10 11]
>>> print(b)
[ 3 4 5 6 7 8 9 10 11]
>>> a[1] = 123
>>> b[2] = 345
>>> print(arr)
[ 0 1 2 3 123 345 6 7 8 9 10 11]
>>> print(id(a),id(b),id(arr[3:]))
54438752 210103936 210104096
变量 a,b 都是 arr 的一部分视图,对视图的修改会直接反映到原数据中。但是我们观察 a,b 的 id,他们是不同的,也就是说,视图虽然指向原数据,但是他们和赋值引用还是有区别的。
副本或深拷贝
ndarray.copy() 函数创建一个副本。 对副本数据进行修改,不会影响到原始数据,它们物理内存不在同一位置
>>> a = np.array([[10,10], [2,3], [4,5]])
>>> print (a)
[[10 10]
[ 2 3]
[ 4 5]]
>>> b = a.copy()
>>> print (b)
[[10 10]
[ 2 3]
[ 4 5]]
>>> print (b is a)
False
>>> b[0,0] = 100
>>> print (b)
[[100 10]
[ 2 3]
[ 4 5]]
>>> print (a)
[[10 10]
[ 2 3]
[ 4 5]]
IO
Numpy 可以读写磁盘上的文本数据或二进制数据。
NumPy 为 ndarray 对象引入了一个简单的文件格式:npy。
npy 文件用于存储重建 ndarray 所需的数据、图形、dtype 和其他信息。
常用的 IO 函数有:
- load() 和 save() 函数是读写文件数组数据的两个主要函数,默认情况下,数组是以未压缩的原始二进制格式保存在扩展名为 .npy 的文件中。
- savez() 函数用于将多个数组写入文件,默认情况下,数组是以未压缩的原始二进制格式保存在扩展名为 .npz 的文件中。
- loadtxt() 和 savetxt() 函数处理正常的文本文件(.txt 等)
numpy.save() 函数将数组保存到以 .npy 为扩展名的文件中。
numpy.save(file, arr, allow_pickle=True, fix_imports=True)
参数说明:
- file:要保存的文件,扩展名为 .npy,如果文件路径末尾没有扩展名 .npy,该扩展名会被自动加上。
- arr: 要保存的数组
- allow_pickle: 可选,布尔值,允许使用 Python pickles 保存对象数组,Python 中的 pickle 用于在保存到磁盘文件或从磁盘文件读取之前,对对象进行序列化和反序列化。
- fix_imports: 可选,为了方便 Pyhton2 中读取 Python3 保存的数据。
>>> import numpy as np
>>> a = np.array([1,2,3,4,5])
# 保存到 outfile.npy 文件上
>>> np.save('outfile.npy',a)
#找不到文件的可以放桌面,看自己桌面路径是啥,改一下
>>> np.save(r'C:\Users\MARS\Desktop\outfile.npy',a)
# 保存到 outfile2.npy 文件上,如果文件路径末尾没有扩展名 .npy,该扩展名会被自动加上
>>> np.save('outfile2',a)
我们可以查看文件内容,win10命令行下:
C:\Users\MARS\AppData\Local\Programs\Python\Python36-32>type outfile.npy
揘UMPYv{'descr': '<i4', 'fortran_order': False, 'shape': (5,), }
C:\Users\MARS\AppData\Local\Programs\Python\Python36-32>type outfile2.npy
揘UMPYv{'descr': '<i4', 'fortran_order': False, 'shape': (5,), }
C:\Users\MARS\AppData\Local\Programs\Python\Python36-32>
可以看出文件是乱码的,因为它们是 Numpy 专用的二进制格式后的数据。
我们可以使用 load() 函数来读取数据就可以正常显示了:
>>> b = np.load('outfile.npy')
>>> print(b)
[1 2 3 4 5]
numpy.savez() 函数将多个数组保存到以 npz 为扩展名的文件中。
numpy.savez(file, *args, **kwds)
参数说明:
- file:要保存的文件,扩展名为 .npz,如果文件路径末尾没有扩展名 .npz,该扩展名会被自动加上。
- args: 要保存的数组,可以使用关键字参数为数组起一个名字,非关键字参数传递的数组会自动起名为 arr_0, arr_1, … 。
- kwds: 要保存的数组使用关键字名称。
>>> a = np.array([[1,2,3],[4,5,6]])
>>> b = np.arange(0, 1.0, 0.1)
>>> c = np.sin(b)
>>> np.savez("wutenglan.npz",a, b, sin_array = c)
>>> r = np.load("wutenglan.npz")
>>> print(r)
<numpy.lib.npyio.NpzFile object at 0x0C7D8190>
>>> print(r["arr_0"])
[[1 2 3]
[4 5 6]]
>>> print(r["arr_1"])
[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
>>> print(r["sin_array"])
[0. 0.09983342 0.19866933 0.29552021 0.38941834 0.47942554
0.56464247 0.64421769 0.71735609 0.78332691]
savetxt() 函数是以简单的文本文件格式存储数据,对应的使用 loadtxt() 函数来获取数据( 可以直接txt打开查看)。
np.loadtxt(FILENAME, dtype=int, delimiter=' ') np.savetxt(FILENAME, a, fmt="%d", delimiter=",")
参数 delimiter 可以指定各种分隔符、针对特定列的转换器函数、需要跳过的行数等。
>>> a = np.array([1,2,3,4,5])
>>> np.savetxt('xiaoze.txt',a)
>>> b = np.loadtxt('xiaoze.txt')
>>> print(b)
[1. 2. 3. 4. 5.]
C:\Users\MARS\AppData\Local\Programs\Python\Python36-32>type xiaoze.txt
1.000000000000000000e+00
2.000000000000000000e+00
3.000000000000000000e+00
4.000000000000000000e+00
5.000000000000000000e+00
使用 delimiter 参数:
>>> a=np.arange(0,10,0.5).reshape(4,-1)
>>> a
array([[0. , 0.5, 1. , 1.5, 2. ],
[2.5, 3. , 3.5, 4. , 4.5],
[5. , 5.5, 6. , 6.5, 7. ],
[7.5, 8. , 8.5, 9. , 9.5]])
>>> np.savetxt("out.txt",a,fmt="%d",delimiter=",") # 改为保存为整数,以逗号分隔
>>> b = np.loadtxt("out.txt",delimiter=",") # load 时也要指定为逗号分隔
>>> print(b)
[[0. 0. 1. 1. 2.]
[2. 3. 3. 4. 4.]
[5. 5. 6. 6. 7.]
[7. 8. 8. 9. 9.]]
C:\Users\MARS\AppData\Local\Programs\Python\Python36-32>type out.txt
0,0,1,1,2
2,3,3,4,4
5,5,6,6,7
7,8,8,9,9