NumPy ndarray多维数组操作详解:创建、属性、运算与索引
本文详细介绍NumPy中ndarray多维数组的核心操作。涵盖从随机生成、列表转换到使用zeros、empty和arange创建数组的方法;解析shape、ndim、dtype等关键属性;演示类型转换与截断机制;深入讲解数组数学运算、基础切片、布尔索引及花式索引(Fancy indexing)的高级用法,并介绍reshape、transpose和swapaxes等数组变换技巧,助力高效进行数据分析。
简介
NumPy的核心功能之一在于处理多维数组,这种对象被称为ndarray。基于ndarray,用户可以执行多种复杂的数学计算任务。
本文将介绍一些常见且基础的ndarray操作,这些技巧在数据分析场景中非常实用。
创建ndarray
生成ndarray的方式多样,例如可以使用np.random模块随机生成数据:
import numpy as np
# Generate some random data
data = np.random.randn(2, 3)
data
array([[ 0.0929, 0.2817, 0.769 ],
[ 1.2464, 1.0072, -1.2962]])
除了随机生成,还可以直接从Python列表(list)中创建数组:
data1 = [6, 7.5, 8, 0, 1]
arr1 = np.array(data1)
array([6. , 7.5, 8. , 0. , 1. ])
从嵌套列表创建多维数组的示例如下:
data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
arr2 = np.array(data2)
array([[1, 2, 3, 4],
[5, 6, 7, 8]])
利用np.zeros可以创建初始值全为0的数组:
np.zeros(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
创建一个2维数组的示例:
np.zeros((3, 6))
array([[0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0.]])
使用empty可以创建3维数组:
np.empty((2, 3, 2))
array([[[0., 0.],
[0., 0.],
[0., 0.]],
[[0., 0.],
[0., 0.],
[0., 0.]]])
需要注意的是,虽然示例中empty创建的数组显示为0,但这并非必然结果。empty函数仅从内存中分配空间并返回,不保证空间内无残留值。因此,使用empty创建数组后,正式使用前务必进行初始化操作。
使用arange可以创建指定范围的数组:
np.arange(15)
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
在创建数组时,可以明确指定元素的数据类型(dtype):
arr1 = np.array([1, 2, 3], dtype=np.float64)
arr2 = np.array([1, 2, 3], dtype=np.int32)
ndarray的属性
通过data.shape可以获取数组的形状信息。
data.shape
(2, 3)
利用ndim属性可以获取数组的维数信息:
arr2.ndim
2
通过data.dtype可以查看数组中元素的具体数据类型。
data.dtype
dtype('float64')
ndarray中元素的类型转换
在创建特定类型的ndarray后,还可以对其数据类型进行转换:
arr = np.array([1, 2, 3, 4, 5])
arr.dtype
dtype('int64')
float_arr = arr.astype(np.float64)
float_arr.dtype
dtype('float64')
上述代码展示了如何使用astype方法,将int64类型的ndarray转换为float64类型。
如果目标数据类型无法容纳原数据的范围,系统会自动执行截断操作:
arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
arr.astype(np.int32)
array([ 3, -1, -2, 0, 12, 10], dtype=int32)
请注意,此处执行的是截断处理,而非向上或向下取整。
ndarray的数学运算
数组既可与常量进行运算,也可与其他数组进行运算:
arr = np.array([[1., 2., 3.], [4., 5., 6.]])
arr * arr
array([[ 1., 4., 9.],
[16., 25., 36.]])
arr + 10
array([[11., 12., 13.],
[14., 15., 16.]])
arr - arr
array([[0., 0., 0.],
[0., 0., 0.]])
1 / arr
array([[1. , 0.5 , 0.3333],
[0.25 , 0.2 , 0.1667]])
arr ** 0.5
array([[1. , 1.4142, 1.7321],
[2. , 2.2361, 2.4495]])
数组之间还可以进行比较运算,比较的是数组中对应元素的大小:
arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])
arr2 > arr
array([[False, True, False],
[ True, False, True]])
index和切片
基本使用
首先了解index和切片的基本用法。index的使用方式与普通数组类似,主要用于访问数组中的特定元素。
使用切片时需注意,切片返回的数组元素是原数组元素的引用。因此,修改切片后的数组会直接影响原数组。
# 构建一维数组
arr = np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# index访问
arr[5]
5
# 切片访问
arr[5:8]
array([5, 6, 7])
# 切片修改
arr[5:8] = 12
array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
# 切片可以修改原数组的值
arr_slice = arr[5:8]
arr_slice[1] = 12345
arr
array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8,
9])
# 构建二维数组
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[2]
array([7, 8, 9])
# index 二维数组
arr2d[0][2]
3
# index二维数组
arr2d[0, 2]
3
# 构建三维数组
arr3d = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
arr3d
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
# index三维数组
arr3d[0]
array([[1, 2, 3],
[4, 5, 6]])
# copy是硬拷贝,和原数组的值相互不影响
old_values = arr3d[0].copy()
arr3d[0] = 42
arr3d
array([[[42, 42, 42],
[42, 42, 42]],
[[ 7, 8, 9],
[10, 11, 12]]])
arr3d[0] = old_values
arr3d
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
# index 三维数组
arr3d[1, 0]
array([7, 8, 9])
x = arr3d[1]
x
array([[ 7, 8, 9],
[10, 11, 12]])
x[0]
array([7, 8, 9])
index with slice
切片(slice)还可以作为index使用,此时它表示一个索引范围值。
作为index使用的slice可以有多种表现形式。
包含起始和结束值的写法,表示索引从1开始,到6-1结束:
arr[1:6]
array([ 1, 2, 3, 4, 64])
省略起始值的写法,表示索引从0开始,到末尾-1结束:
arr2d[:2]
array([[1, 2, 3],
[4, 5, 6]])
省略结束值的写法,表示从起始位置开始,直到所有数据结束:
arr2d[:2, 1:]
array([[2, 3],
[5, 6]])
arr2d[1, :2]
array([4, 5])
boolean index
index还可以使用布尔值,用于筛选是否选择该索引对应的数据。
首先看如何构建一个布尔类型的数组:
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
names == 'Bob'
array([ True, False, False, True, False, False, False])
上述代码通过比较操作,返回了一个仅包含True和False的数组。
该布尔数组可作为index值来访问原数组:
# 构建一个7 * 4 的数组
data = np.random.randn(7, 4)
array([[ 0.275 , 0.2289, 1.3529, 0.8864],
[-2.0016, -0.3718, 1.669 , -0.4386],
[-0.5397, 0.477 , 3.2489, -1.0212],
[-0.5771, 0.1241, 0.3026, 0.5238],
[ 0.0009, 1.3438, -0.7135, -0.8312],
[-2.3702, -1.8608, -0.8608, 0.5601],
[-1.2659, 0.1198, -1.0635, 0.3329]])
# 通过boolean数组来访问:
data[names == 'Bob']
array([[ 0.275 , 0.2289, 1.3529, 0.8864],
[-0.5771, 0.1241, 0.3026, 0.5238]])
在索引行时,还可以同时指定列:
data[names == 'Bob', 3]
array([0.8864, 0.5238])
可以使用~符号来执行取反操作:
data[~(names == 'Bob')]
array([[-2.0016, -0.3718, 1.669 , -0.4386],
[-0.5397, 0.477 , 3.2489, -1.0212],
[ 0.0009, 1.3438, -0.7135, -0.8312],
[-2.3702, -1.8608, -0.8608, 0.5601],
[-1.2659, 0.1198, -1.0635, 0.3329]])
通过布尔型数组设置值,在实际项目中非常有用:
data[data < 0] = 0
array([[0.275 , 0.2289, 1.3529, 0.8864],
[0. , 0. , 1.669 , 0. ],
[0. , 0.477 , 3.2489, 0. ],
[0. , 0.1241, 0.3026, 0.5238],
[0.0009, 1.3438, 0. , 0. ],
[0. , 0. , 0. , 0.5601],
[0. , 0.1198, 0. , 0.3329]])
data[names != 'Joe'] = 7
array([[7. , 7. , 7. , 7. ],
[0. , 0. , 1.669 , 0. ],
[7. , 7. , 7. , 7. ],
[7. , 7. , 7. , 7. ],
[7. , 7. , 7. , 7. ],
[0. , 0. , 0. , 0.5601],
[0. , 0.1198, 0. , 0.3329]])
Fancy indexing
Fancy indexing(花式索引)是指使用一个整数数组来进行索引操作。
举例来说,我们先创建一个8 * 4的数组:
arr = np.empty((8, 4))
for i in range(8):
arr[i] = i
arr
array([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.],
[4., 4., 4., 4.],
[5., 5., 5., 5.],
[6., 6., 6., 6.],
[7., 7., 7., 7.]])
然后使用一个整数数组进行索引,这将按照指定顺序选择行:
arr[[4, 3, 0, 6]]
array([[4., 4., 4., 4.],
[3., 3., 3., 3.],
[0., 0., 0., 0.],
[6., 6., 6., 6.]])
还可以使用负值进行索引:
arr[[-3, -5, -7]]
array([[5., 5., 5., 5.],
[3., 3., 3., 3.],
[1., 1., 1., 1.]])
花式索引还可以组合使用:
arr = np.arange(32).reshape((8, 4))
arr
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23],
[24, 25, 26, 27],
[28, 29, 30, 31]])
上述代码构建了一个8 * 4的数组。
arr[[1, 5, 7, 2], [0, 3, 1, 2]]
array([ 4, 23, 29, 10])
接着选取第2列的第一个值、第6列的第三个值等,最终得到一个1维数组。
数组变换
我们可以在不同维度的数组之间进行变换,还可以转换数组的轴。
reshape方法可以将数组转换为任意形状:
arr = np.arange(15).reshape((3, 5))
arr
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
数组还提供了一个T属性,用于将数组的轴进行对调:
arr.T
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
对于高维数组,可以使用transpose来进行轴的转置:
arr = np.arange(16).reshape((2, 2, 4))
arr
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
arr.transpose((1, 0, 2))
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
如何理解上面的transpose((1, 0, 2))?
其含义是将x轴和y轴对调,z轴保持不变。
上述代码通过reshape((2, 2, 4))方法创建了一个3维(即3个轴)的数组,其shape为2 * 2 * 4。
首先看下转换前的对应关系:
(0,0)-》 [ 0, 1, 2, 3]
(0,1)-》 [ 4, 5, 6, 7]
(1,0)-》 [ 8, 9, 10, 11]
(1,1)-》 [12, 13, 14, 15]
转换之后:
(0,0)-》 [ 0, 1, 2, 3]
(0,1)-》 [ 8, 9, 10, 11]
(1,0)-》[ 4, 5, 6, 7]
(1,1)-》 [12, 13, 14, 15]
由此得到了上述的结果。
多维数组的轴转换可能较为复杂,建议多加理解。
还可以使用swapaxes来交换两个轴,上述例子可以重写为:
arr.swapaxes(0,1)
到此这篇关于NumPy实现ndarray多维数组操作的文章就介绍到这了,更多相关NumPy ndarray多维数组操作内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









