ndarray:多维数组对象 实质上是一个大数据容器
本文以《利用Python进行数据分析》为基础
1.生成ndarry
(1)使用array函数。array函数接受任意的序列型对象,生成一个新的包含传递数据的NumPy数组。
import numpy as np
data1 = [6,7.5,8,0,1]
arr1 = np.array(data1)
print(arr1)
[6. 7.5 8. 0. 1. ]
嵌套的序列:
data2 = [[1,2,3,4],[5,6,7,8]]
arr2 = np.array(data2)
print(arr2)
[[1 2 3 4]
[5 6 7 8]]
data2是一个包含列表的列表,所以NumPy数组arr2形成了一个二维数组,可以通过ndim和shape属性来确认这点
print(arr2.ndim) #ndim用来查看数组维数
print(arr2.shape) #shape用来查看数组行列数
2
(2, 4)
除非显示的指定,否则np.array会自动推断生成数组的数据类型。数据类型被存储在一个特殊的元数据dtype中,例如之前的两个例子:
print(arr2.dtype)
int32
除了np.array,还有很多其他函数可以创建新数组。
例如:给定长度和形状后,zeros可以一次性的创造全0数组,ones可以一次性创造全1数组。empty可以创建没有初始化数值的数组。创建高维数组,需要向shape传递一个元组:
a = np.zeros(10)
b = np.zeros((3,6))
print(a)
print(b)
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[[0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0.]]
c = np.empty((2,3,2))
print(c)
[[[6.23042070e-307 4.67296746e-307]
[1.69121096e-306 1.16820707e-307]
[1.89146896e-307 1.37961302e-306]]
[[1.05699242e-307 8.01097889e-307]
[1.37962388e-306 6.89805151e-307]
[1.78020169e-306 1.42410974e-306]]]
此处使用empty并未生成一个全0的数组,因为使用empty生成一个全0数组是不安全的,有时候他可能返回初始化的垃圾数值
此处生成数组还有一个函数arange,它是Python内建函数range的数组版
a = np.arange(15)
print(a)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
数组生成函数
函数名 | 描述 |
---|---|
array | 将输入数据(可以是列表,元组,数组以及其他序列) 转换为ndarray,如不显式的指明数据类型,将自动推断;默认复制所有的输入数据 |
asarray | 将输入转换为ndarry,但如果输入已经是ndarray则不再复制 |
arange | Python内建函数range的数组版,返回一个数组 |
ones | 根据给定形状和数据类型生成一个全1数组 |
ones_like | 根据所给定的数组生成一个形状一样的全1数组 |
zeros | 根据所给定形状和数据类型生成全0数组 |
zeros_like | 根据所给定的数组生成一个形状一样的全0数组 |
2.ndarray的数据类型
数据类型,即dtype,是一个特殊的对象(表示数据的数据)。
arr1 = np.array([1,2,3],dtype = np.float64)
arr2 = np.array([1,2,3],dtype = np.int32)
print(arr1.dtype)
print(arr2.dtype)
float64
int32
dtype是NumPy能与其他系统灵活交互的原因。数据的dtype通常都按照一个方式命名:类型名,比如float和int,后面接上表明每个元素位数的数字。
不要担心如何记住NumPy的数据类型,尤其是当你还是新手的时候。通常你只需要关心数据的大类,比如是否是浮点型,整数,布尔值,字符串或者某个Python对象。当你需要在内存或硬盘上做更深入的存取操作时,尤其是大数据集时,你才真正需要了解数据的数据类型。
Numpy数据类型
类型 | 类型代码 | 描述 |
---|---|---|
int8,uint8 | i1,u1 | 有符号和无符号的8位整数 |
int16,uint16 | i2,u2 | 有符号和无符号的16位整数 |
float16 | f2 | 半精度浮点数 |
float32 | f或f4 | 标准单精度浮点数;兼容C语言float |
bool | ? | 布尔值,存储True或False |
我只罗列了部分的数据类型
你可以使用astype方法显式地转换数组的数据类型:
arr = np.array([1,2,3,4,5])
print(arr.dtype)
float_arr = arr.astype(np.float64)
print(float_arr.dtype)
int32
float64
上面的例子中,整数被转换成了浮点数。如果我把浮点数转换成整数,则小数点后的部分被消除:
arr = np.array([3.7,-1.2,-2.6,0.5,12.9,10.1])
print(arr)
print(arr.astype(np.int32))
[ 3.7 -1.2 -2.6 0.5 12.9 10.1]
[ 3 -1 -2 0 12 10]
如果你有一个数组,里面的元素都是表达数字含义的字符串,也可以通过astype将字符串转换为数字:
numeric_strings = np.array(['1.25','-9.6','42'],dtype = np.string_)
print(numeric_strings.astype(float))
[ 1.25 -9.6 42. ]
在NumPy中,当使用numpy.string_类型作字符串数据要小心,因为NumPy会修正它的大小或删除输入且不触发警告。使用astype总是生成一个新数组,即使你传入的dtype与之前一样
3.NumPy数组算术
数组之所以重要是因为它允许你进行批量操作而无任何for循环。NumPy用户称这种特性为向量化。任何两个等尺寸之间的算术操作都应用了逐元素操作的方式:
arr = np.array([[1.,2.,3.],[4.,5.,6.]])
print(arr)
print(arr * arr)
print(arr - arr)
[[1. 2. 3.]
[4. 5. 6.]]
[[ 1. 4. 9.]
[16. 25. 36.]]
[[0. 0. 0.]
[0. 0. 0.]]
带有标量计算的算术操作,会把计算参数传递给数组的每一个元素:
a = 1/arr
b = arr ** 0.5
print(a)
print(b)
[[1. 0.5 0.33333333]
[0.25 0.2 0.16666667]]
[[1. 1.41421356 1.73205081]
[2. 2.23606798 2.44948974]]
同尺寸数组之间的比较,会产生一个布尔值数组:
arr = np.array([[1.,2.,3.],[4.,5.,6.]])
arr2 = np.array([[0.,4.,1.],[7.,2.,12.]])
a = arr2 > arr
print(a)
[[False True False]
[ True False True]]
不同尺寸的数组间的操作,将会用到广播特性
4.基础索引与切片
NumPy数组索引是一个大话题,有很多方式可以让你选中数据的子集或某个单个元素。一维数组比较简单。看起来和Python的列表很类似:
arr = np.arange(10)
print(arr)
[0 1 2 3 4 5 6 7 8 9]
a = arr[5]
print(a)
b = arr[5:8]
print(b)
5
[5 6 7]
arr[5:8] = 12
print(arr)
[ 0 1 2 3 4 12 12 12 8 9]
如你所见,如果你传入了一个数值给数组的切片,例如arr[5:8] = 12,数值被传递给了整个切片。区别于Python的内建列表,数组的切片是原数组的视图。这意味着数据表并不是被复制了,任何对于视图的修改都会反映到原数组上。
如果你想要一份数组切片的拷贝而不是一份视图的话,你就必须显式的复制这个数组,例如arr[5:8].copy()。
对更高维的数组,你会有更多的选择。在一个二维数组中,每个索引值对应的元素不再是一个值,而是一个一维数组:
arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(arr2d[2])
[7 8 9]
因此,单个元素可以通过递归的方式获得。但是要多写点代码,你可以通过传递一个索引的逗号分隔列表去选择单个元素,以下两种方式效果一样:
print(arr2d[0][2])
print(arr2d[0,2])
3
3
在多维数组中,你可以省略后续索引值,返回的对象将是降低一个维度的数组。因此在一个223的数组arr3d中:
arr3d = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
print(arr3d)
print(arr3d[0])
[[[ 1 2 3]
[ 4 5 6]]
[[ 7 8 9]
[10 11 12]]]
[[1 2 3]
[4 5 6]]
标量和数组都可以传递给arr3d[0]
old_values = arr3d[0].copy()
arr3d[0] = 42
print(arr3d)
[[[42 42 42]
[42 42 42]]
[[ 7 8 9]
[10 11 12]]]
arr3d[0] = old_values
print(arr3d)
[[[ 1 2 3]
[ 4 5 6]]
[[ 7 8 9]
[10 11 12]]]
arr3d[1,0]返回的是一个一维数组
print(arr3d[1,0])
[7 8 9]
#还可以分解为以下步骤
x = arr3d[1]
print(x)
print(x[0])
[[ 7 8 9]
[10 11 12]]
[7 8 9]
以上数组子集选择中,返回的数组都是视图