NumPy(八): 副本和视图&IO

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_0arr_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

猜你喜欢

转载自blog.csdn.net/zcb_data/article/details/110205261
今日推荐