NumPy基础(二)
一、创建数组
(一)将Python array_like对象转换为Numpy数组
个人理解为将python中的列表类型list
转化为ndarry
类型
import numpy as np
x = np.array([2,3,1,0])
(二)Numpy原生数组的创建
1. 数组生成函数汇总
函数名 | 描述 |
---|---|
array | 将输入数据转换为ndarray,如不显式指明数据类型,将自行判断;默认复制所有的输入数据 |
asarray | 将输入转换为ndarray,但如果输入已经是ndarray则不再复制 |
arange | Python内建函数range的数组版,返回一个数组 |
ones | 根据给定形状和数据类型生成全1数组 |
ones_like | 根据所给的数组生成一个形状一样的全1数组 |
zeros | 根据给定形状和数据类型生成全0数组 |
zeros_like | 根据所给的数组生成一个形状一样的全0数组 |
empty | 根据给定形状生成一个没有初始化的空数组 |
empty_like | 根据所给的数组生成一个形状一样但没有初始化的数组 |
full | 根据给定形状和数据类型生成指定数值的数组 |
full_like | 根据所给的数组生成一个形状一样但内容是指定数值的数组 |
linspace | 创建具有指定数量元素的数组,并在指定的开始值和结束值之间平均间隔。 |
indices | 创建一组可以表示每个维度变化的数组。 |
eye,identity | 生成一个 N × N N\times N N×N特征矩阵(对角线1,其余0) |
2. zeros()
我们可以使用zeros()
函数创建一个全为0的数组,数组的默认dtype
是float64
。
import numpy as np
x = np.zeros((2, 3), dtype=np.int_)
3. ones()
同样的,我们可以使用ones()
创建一个全为1的数组,用法与zeros()
相同。
import numpy as np
x = np.ones((2, 3), dtype=np.int_)
4. empty()
我们也可以使用empty()
创建一个没有初始化数值的数组。
import numpy as np
x = np.empty((2, 4))
5. nidm、shape
我们可以通过检查nidm
和shape
属性检查建立的数组。
>>> import numpy as np
>>> x = np.zeros((2, 4, 3))
>>> x.nidm # 返回维数,这里为三维数组
3
>>> x.shape
(2, 4, 3) # 返回数组的具体结构
6. arange()
与python中range()
类似,可以使用arange()
创建具有有规律递增值的数组。
>>> import numpy as np
>>> np.arange(10) # 输出从0到9的数组(相当于省略初始值)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.arange(2, 10) # 输出从2到9的数组
array([2, 3, 4, 5, 6, 7, 8, 9])
>>> np.arange(2, 10, 3) # 输出从2到9的数组,步长为3
array([2, 5, 8])
>>>np.arange(2, 4, dtype = np.int_) # 设置数据类型(无小数默认为int32,小数默认为float64)
7. linspace()
我们可以使用linspace()
来创建一个包含始末数字的数组,其中数组的长度可以指定。默认数据类型为float64
。
>>> import numpy as np
>>> np.linspace(2, 4, 3)
array([2., 3., 4.])
8. indices()
indices()
将创建一组数组(堆积为一个更高维的数组),每个维度一个,每个维度表示该维度中的变化。
>>> import numpy as np
>>> np.indices((3,3))
array([[[0, 0, 0], # 这一边从上至下递加
[1, 1, 1],
[2, 2, 2]],
[[0, 1, 2], # 这一边从左至右递加
[0, 1, 2],
[0, 1, 2]]])
(三)从硬盘中读取数组
二、NumPy与输入输出
(一)NumPy内建二进制格式
np.save
和np.load
是高效存储硬盘数据的两大工具函数。数组在默认情况下是以未压缩的格式进行存储的,后缀名是.npy
1. save()
我们可以通过np.save
保存数组,如果文件存放路径中没写,会自动补上.npy
。
import numpy as np
x = np.ones((2, 4))
np.save('1', x)
2. load()
硬盘上的数组可以通过np.load
进行载入
import numpy as np
x = np.load('1.npy')
print(x)
3. savez()
我们可以使用savez
并将数组作为参数传递给该函数,用于在压缩文件(.npz)中保存多个数组
import numpy as np
x = np.ones((2, 4))
y = np.zeros((2, 4))
np.savez('1', a=x, b=y) # 通过键值对(字典)的形式创建文件
当我们载入一个.npz
文件时,会获得一个字典。
import numpy as np
arch = np.load("1.npz") # 读取文件".npz"
print(arch['a']) # 读取键'a'的值
4. savez_compressed
如果你的数据已经压缩好了,你可能会想要使用np.savez_compressed将数据存入已经压缩好的文件。
import numpy as np
z = np.zeros((5, 4))
np.savez_compressed('1.npz', c=z) # 创建键值对c-->z
(二)使用genfromtxt导入数据
首先,我们新建 1.txt 用于储存数据
1,2,3,4,5
6,7,8,9,10
1. 定义输入
genfromtxt
的唯一强制参数是数据的来源。它可以是一个字符串,一串字符串或一个生成器(file
, str
, pathlib.Path
, list of str
, 或者generator
)。如果提供了单个字符串,则假定它是本地或远程文件的名称,或者带有read
方法的开放文件类对象。如果提供了字符串列表或生成器返回字符串,则每个字符串在文件中被视为一行。当传递远程文件的URL时,该文件将自动下载到当前目录并打开。
同时,genfromtxt
还可以自动识别文件是否是压缩类型,目前支持两种压缩类型:gzip
和bz2
。
2. 将行拆分为列
(1)delimiter参数
一旦文件被定义并打开进行读取,genfromtxt
会将每个非空行分割为一串字符串。 空的或注释的行只是略过。 delimiter
关键字用于定义拆分应该如何进行。
- 根据字符来分割:
>>> import numpy as np
>>> np.genfromtxt("1.txt", delimiter=",")
array([[ 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10.]])
- 根据空格来分割:
为方便展示,我们重写 1.txt 中的数据
1 2 3 4 5
6 7 8 9 10
在书写时,我们故意将后几位的空格拉长。
默认情况下,genfromtxt假定delimiter=None
,这意味着该行沿着空白区域(包括制表符)分割,并且连续的空白区域被视为单个空白区域。
>>> import numpy as np
>>> np.genfromtxt("1.txt") # 读取"1.txt"中的数据
array([[ 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10.]])
- 根据字符长度来分割:
此时,1.txt 中的数据如下
1234
5678
在这种情况下,我们需要将delimiter
设置为单个整数(如果所有列的大小相同)或整数序列(如果列的大小可能不同):
>>> import numpy as np
>>> np.genfromtxt("1.txt", delimiter=1) # delimiter为单个整数
array([[1., 2., 3., 4.],
[5., 6., 7., 8.]])
>>> np.genfromtxt("1.txt", delimiter=(2, 1)) # delimiter为整数序列
array([[12., 3.],
[56., 7.]])
(2)autostrip参数
当配置autostrip=True
,python会自动删除分割后字符的前后空格。
1.txt 文件如下:
1, 2,3, 4
5 , 6 , 7, 8
功能实现如下:
>>> import numpy as np
>>> np.genfromtxt("1.txt", delimiter=',', dtype=str)
array([['1', ' 2', '3', ' 4'],
['5 ', ' 6 ', ' 7', ' 8']], dtype='<U5')
>>> np.genfromtxt("1.txt", delimiter=',', dtype=str, autostrip=True)
array([['1', '2', '3', '4'],
['5', '6', '7', '8']], dtype='<U1')
我们发现在输出中,所以开头和结尾的空格被删除。
其中:dtype='<U1'
中:
- <表示字节顺序,小端(最小有效字节存储在最小地址中)
- U表示Unicode,数据类型
- 1表示元素位长,数据大小
(3)comments参数
可选参数comments
用于定义标记注释开始的字符串。默认情况下,genfromtxt
假定comments='#'
。
我们首先重新编辑 1.txt 中的内容:
1,2,3//123
//456
4,5,6
代码实现:
>>> import numpy as np
>>> np.genfromtxt("1.txt", delimiter=',', comments='//') # 以'//'为注释标志
array([[1., 2., 3.],
[4., 5., 6.]])
我们发现,这里的注释规则与python中#
一致。
注意
这种行为有一个明显的例外:如果可选参数names=True
,则会检查第一条注释行的名称。
3. 跳过直线并选择列
(1)skip_header和skip_footer参数
skip_header
和skip_footer
参数用来跳过开头/末尾的某些行,我们可以通过控制参数的取值控制开头/结尾忽略的行数,默认情况下skip_header
和skip_footer
均等于0。
首先我们编辑一下 1.txt 中的数据
1,2,3
4,5,6
7,8,9
代码实现:
>>> import numpy as np
>>> np.genfromtxt("1.txt", delimiter=',', skip_header=1) # 忽略第一行
array([[4., 5., 6.],
[7., 8., 9.]])
>>> np.genfromtxt("1.txt", delimiter=',', skip_footer=2) # 忽略后两行
array([1., 2., 3.])
(2)usecols参数
我们可以通过usecols
参数来指定读取哪些列。该参数接受与要导入的列的索引相对应的单个整数或整数序列。按照惯例,第一列的索引为0。负整数的行为与常规Python负向索引相同。
本例中, 1.txt 文件同上,下面是代码实现。
>>> import numpy as np
>>> np.genfromtxt("1.txt", delimiter=',', usecols=1) # 取第二列
array([2., 5., 8.])
>>> np.genfromtxt("1.txt", delimiter=',', usecols=(1, 2)) # 取第二至三列
array([[2., 3.],
[5., 6.],
[8., 9.]])
我们还可以通过列名指定需要的哪些行:
下面我们将用三种方式指定第一、三行,代码如下
>>> import numpy as np
>>> np.genfromtxt("1.txt", delimiter=',',
names='a, b, c', usecols=('a', 'c')) # 通过字符串序列指定
array([(1., 3.), (4., 6.), (7., 9.)], dtype=[('a', '<f8'), ('c', '<f8')])
>>> np.genfromtxt("1.txt", delimiter=',',
names='a, b, c', usecols='a, c') # 通过逗号分隔字符串指定
array([(1., 3.), (4., 6.), (7., 9.)], dtype=[('a', '<f8'), ('c', '<f8')])
>>> np.genfromtxt("1.txt", delimiter=',',
names='a, b, c', usecols=('a', 2)) # 混合方式指定
array([(1., 3.), (4., 6.), (7., 9.)], dtype=[('a', '<f8'), ('c', '<f8')])
4. 选择数据的类型
控制我们从文件中读取的字符串序列如何转换为其他类型的主要方法是设置dtype
参数。这个参数的可接受值是:
- 单一类型,如
dtype=float
。除非使用names
参数将名称与每个列关联(见下文),否则输出将是给定dtype的2D格式。请注意,dtype=float
是genfromtxt
的默认值。 - 一系列类型,如
dtype=(int, float, float)
。 - 逗号分隔的字符串,例如
dtype="i4,f8,|S3"
。 - 一个包含两个键
'names'
和'formats'
的字典。 - 一个元组序列
(name, type)
, 像dtype=[('A', int), ('B', float)]
。 - 现有的
numpy.dtype
对象。 - 特殊值
None
。在这种情况下,列的类型将根据数据本身确定(见下文)。
在所有情况下,除了第一种情况,输出将是一个带有结构化dtype
的一维数组。这个dtype
与序列中的项目一样多。字段名称由names
关键字定义。
当dtype=None
时,每列的类型由其数据迭代确定。我们首先检查一个字符串是否可以转换为布尔值(也就是说,如果字符串在小写字母中匹配true
或false
);然后是否可以将其转换为整数,然后转换为浮点数,然后转换为复数并最终转换为字符串。通过修改StringConverter
类的默认映射器可以更改此行为。
5. 设置名称
(1)结构化dtype
在上面我们曾遇到过这样的数据array([(1., 3.), (4., 6.), (7., 9.)], dtype=[('a', '<f8'), ('c', '<f8')])
,不难发现他的dtype
信息中包含了列名,我们可以通过设置来定义。
首先,我们的 1.txt 中的数据如下:
1 2 3
4 5 6
7 8 9
下面是python代码
>>> import numpy as np
>>>np.genfromtxt("1.txt", dtype=[(_, int) for _ in "abc"])
array([(1, 2, 3), (4, 5, 6), (7, 8, 9)],
dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<i4')])
(2)names参数
使用names
参数可以让我们更简单的命名
>>> import numpy as np
>>> np.genfromtxt("1.txt", names='a, b, c')
array([(1., 2., 3.), (4., 5., 6.), (7., 8., 9.)],
dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
在上面的例子中,我们使用了默认情况下dtype=float
的事实。通过给出一个名称序列,我们强制输出到一个结构化的dtype
。
names
还支持从数据中读取列名:
我们重新配置一下 1.txt 文件
a b c
1 2 3
4 5 6
7 8 9
下面让我们设置names=True
:
>>> import numpy as np
>>> np.genfromtxt("1.txt", names=True)
array([(1., 2., 3.), (4., 5., 6.), (7., 8., 9.)],
dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
通过上面的代码,我们成功的设置了列名。同时我们发现,即使第一行被注释掉,仍然可以正常读取出列名。即将 1.txt 第一行设置为#a b c
。
names
的默认值为None
。如果我们给关键字赋予任何其他值,新名称将覆盖我们可能用dtype
定义的字段名称:
1.txt:
1 2 3
4 5 6
7 8 9
Python代码:
>>> import numpy as np
>>> ndtype=[('a',int), ('b', float), ('c', int)]
>>> names = ["A", "B", "C"]
>>> np.genfromtxt("1.txt", names=names, dtype=ndtype)
array([(1, 2., 3), (4, 5., 6), (7, 8., 9)],
dtype=[('A', '<i4'), ('B', '<f8'), ('C', '<i4')])
换言之,当我们同时在dtype
和names
中设置列名,names
的优先级更高。
(3)defaultfmt参数
如果 names=None
的时候,只是预计会有一个结构化的dtype
,它的名称将使用标准的NumPy默认值 "f%i"
来定义,会产生例如f0
,f1
等名称:
>>> import numpy as np
>>> np.genfromtxt('1.txt', dtype=(int, float, int))
array([(1, 2., 3), (4, 5., 6), (7, 8., 9)],
dtype=[('f0', '<i4'), ('f1', '<f8'), ('f2', '<i4')])
同样,如果我们没有提供足够的名称来匹配dtype
的长度,缺少的名称将使用此默认模板进行定义:
>>> import numpy as np
>>> np.genfromtxt('1.txt', dtype=(int, float, int), names='a')
array([(1, 2., 3), (4, 5., 6), (7, 8., 9)],
dtype=[('a', '<i4'), ('f0', '<f8'), ('f1', '<i4')])
我们可以使用defaultfmt
参数覆盖此默认值,该参数采用任何格式字符串:
>>> import numpy as np
>>> np.genfromtxt('1.txt', dtype=(int, float, int), defaultfmt="var_%02i")
array([(1, 2., 3), (4, 5., 6), (7, 8., 9)],
dtype=[('var_00', '<i4'), ('var_01', '<f8'), ('var_02', '<i4')])
注意!
我们需要记住,仅当预期一些名称但未定义时才使用defaultfmt
。
(4)验证名称
具有结构化dtype
的NumPy数组也可以被视为recarray
,其中可以像访问属性一样访问字段。因此,我们可能需要确保字段名称不包含任何空格或无效字符,或者它不对应于标准属性的名称(如size
或shape
),这会混淆解释者。genfromtxt
接受三个可选参数,这些参数可以更好地控制名称:
deletechars
- 给出一个字符串,将所有必须从名称中删除的字符组合在一起。默认情况下,无效字符是~!@#$%^&*()-=+~\|]}[{';: /?.>,<
excludelist
- 给出要排除的名称列表,如return
,file
,print
…如果其中一个输入名称是该列表的一部分,则会附加一个下划线字符('_'
)。case_sensitive
- 是否区分大小写(case_sensitive=True
),转换为大写(case_sensitive=False
或case_sensitive='upper'
)或小写(case_sensitive='lower'
)。
6. 快捷方式函数
除了 genfromtxt 之外,numpy.lib.io模块还提供了几个从 genfromtxt 派生的方便函数。这些函数的工作方式与原始函数相同,但它们具有不同的默认值。
- recfromtxt - 返回标准 numpy.recarray(如果
usemask=False
)或 MaskedRecords数组(如果usemaske=True
)。默认dtype是dtype=None
,意味着将自动确定每列的类型。 - recfromcsv - 类似 recfromtxt,但有默认值
delimiter=","
。