numpy基础知识教程:助你轻松上手数据分析 – wiki基地


NumPy 基础知识教程:助你轻松上手数据分析

在数据分析、机器学习和科学计算领域,NumPy (Numerical Python) 是一个绕不开的基础库。它提供了高性能的多维数组对象(ndarray)以及用于处理这些数组的强大工具。毫不夸张地说,NumPy 是 Python 数据科学生态系统的基石,许多其他流行的库(如 Pandas、Scikit-learn、Matplotlib)都建立在 NumPy 之上。

本教程将带你深入了解 NumPy 的核心概念和基本操作,让你能够自信地使用 NumPy 进行数据处理和分析。

1. 为什么选择 NumPy?

在 Python 中,列表(list)也可以用来存储和操作数据,但为什么还要使用 NumPy 呢?主要有以下几个原因:

  • 性能: NumPy 的核心是用 C 语言编写的,这使得它在进行数值计算时速度非常快。NumPy 数组在内存中是连续存储的,而 Python 列表中的元素是分散存储的,这使得 NumPy 能够利用现代 CPU 的向量化指令进行并行计算,从而大幅提高运算效率。
  • 内存效率: NumPy 数组中的元素类型是统一的,而 Python 列表中的元素可以是任意类型。这使得 NumPy 数组占用的内存空间更小,也更易于管理。
  • 功能丰富: NumPy 提供了大量的数学、统计和线性代数函数,可以方便地进行各种数值计算和数据分析操作。
  • 易于使用: NumPy 的 API 设计简洁明了,易于学习和使用。

2. 安装 NumPy

如果你使用 Anaconda Python 发行版,那么 NumPy 已经预装好了。如果没有安装,可以使用以下命令通过 pip 安装:

bash
pip install numpy

或者使用 conda 安装:

bash
conda install numpy

安装完成后,可以在 Python 中导入 NumPy 并查看版本:

“`python
import numpy as np

print(np.version)
“`

3. NumPy 数组(ndarray)

NumPy 的核心是 ndarray(n-dimensional array,多维数组)对象。它是一个由相同类型的元素组成的多维网格。

3.1 创建数组

有多种方法可以创建 NumPy 数组:

  • 从列表或元组创建:

“`python
import numpy as np

从列表创建

arr1 = np.array([1, 2, 3, 4, 5])
print(arr1) # 输出:[1 2 3 4 5]

从元组创建

arr2 = np.array((6, 7, 8, 9, 10))
print(arr2) # 输出:[ 6 7 8 9 10]

创建二维数组(矩阵)

arr3 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr3)

输出:

[[1 2 3]

[4 5 6]]

“`

  • 使用内置函数创建:

“`python

创建全零数组

zeros_arr = np.zeros((3, 4)) # 创建一个3×4的全零数组
print(zeros_arr)

创建全一数组

ones_arr = np.ones((2, 3, 4)) # 创建一个2x3x4的全一数组(三维)
print(ones_arr)

创建单位矩阵

eye_arr = np.eye(5) # 创建一个5×5的单位矩阵
print(eye_arr)

创建指定范围内的数组

range_arr = np.arange(10, 30, 2) # 从10到30(不包括30),步长为2
print(range_arr) # 输出:[10 12 14 16 18 20 22 24 26 28]

创建等差数列

linspace_arr = np.linspace(0, 1, 5) # 从0到1(包括1),生成5个等间距的数
print(linspace_arr) # 输出:[0. 0.25 0.5 0.75 1. ]

创建随机数数组

rand_arr = np.random.rand(2, 3) # 创建一个2×3的随机数数组(0到1之间)
print(rand_arr)

randn_arr = np.random.randn(3, 3) # 创建一个3×3的标准正态分布随机数数组
print(randn_arr)

randint_arr = np.random.randint(1, 100, size=(4,5)) #创建4×5的1到100的随机整数数组
print(randint_arr)
“`

3.2 数组属性

NumPy 数组有一些重要的属性:

  • ndarray.ndim 数组的维度(轴)的数量。
  • ndarray.shape 数组的形状,一个表示每个维度大小的元组。
  • ndarray.size 数组中元素的总数。
  • ndarray.dtype 数组中元素的类型。
  • ndarray.itemsize 数组中每个元素占用的字节数。

“`python
arr = np.array([[1, 2, 3], [4, 5, 6]])

print(“维度:”, arr.ndim) # 输出:维度: 2
print(“形状:”, arr.shape) # 输出:形状: (2, 3)
print(“元素总数:”, arr.size) # 输出:元素总数: 6
print(“元素类型:”, arr.dtype) # 输出:元素类型: int64 (或 int32,取决于系统)
print(“每个元素字节数:”, arr.itemsize) # 输出:每个元素字节数: 8 (或 4)
“`

3.3 数据类型

NumPy 支持多种数据类型,包括:

  • 整数: int8, int16, int32, int64, uint8, uint16, uint32, uint64
  • 浮点数: float16, float32, float64, float128
  • 复数: complex64, complex128, complex256
  • 布尔值: bool
  • 字符串: string_, unicode_

在创建数组时,可以指定数据类型:

python
arr = np.array([1, 2, 3], dtype=np.float32)
print(arr.dtype) # 输出:float32

也可以使用 astype() 方法转换数据类型:

python
arr = np.array([1, 2, 3])
float_arr = arr.astype(np.float64)
print(float_arr.dtype) # 输出:float64

4. 数组索引和切片

NumPy 数组的索引和切片与 Python 列表类似,但更加强大和灵活。

4.1 一维数组

“`python
arr = np.arange(10)
print(arr) # [0 1 2 3 4 5 6 7 8 9]

获取单个元素

print(arr[3]) # 输出:3

切片

print(arr[2:5]) # 输出:[2 3 4] (从索引2到5,不包括5)
print(arr[:4]) # 输出:[0 1 2 3] (从开头到索引4,不包括4)
print(arr[6:]) # 输出:[6 7 8 9] (从索引6到结尾)
print(arr[::2]) # 输出:[0 2 4 6 8] (从开头到结尾,步长为2)
print(arr[::-1]) # 输出:[9 8 7 6 5 4 3 2 1 0] (反转数组)

使用负数索引

print(arr[-1]) # 输出:9 (最后一个元素)
print(arr[-3:]) # 输出:[7 8 9] (最后三个元素)
“`

4.2 多维数组

“`python
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr)

[[1 2 3]

[4 5 6]

[7 8 9]]

获取单个元素

print(arr[1, 2]) # 输出:6 (第2行第3列的元素,索引从0开始)

切片

print(arr[0:2, 1:3]) # 输出:[[2 3] [5 6]] (第1、2行,第2、3列)
print(arr[:, 1]) # 输出:[2 5 8] (所有行的第2列)
print(arr[1, :]) # 输出:[4 5 6] (第2行的所有列)

使用布尔索引

bool_index = arr > 5
print(bool_index)

[[False False False]

[False False True]

[ True True True]]

print(arr[bool_index]) # 输出:[6 7 8 9] (所有大于5的元素)
print(arr[arr > 5]) # 与上一行等价,更简洁的写法

使用整数数组索引

rows = np.array([0, 2])
cols = np.array([1, 2])
print(arr[rows, cols]) # 输出:[2 9] (获取(0,1)和(2,2)位置的元素)
“`

5. 数组运算

NumPy 提供了丰富的数组运算功能,包括基本的算术运算、数学函数、统计函数、线性代数运算等。

5.1 算术运算

NumPy 数组支持标准的加、减、乘、除、幂等运算。这些运算是按元素进行的(element-wise)。

“`python
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])

print(a + b) # 输出:[ 6 8 10 12]
print(a – b) # 输出:[-4 -4 -4 -4]
print(a * b) # 输出:[ 5 12 21 32]
print(a / b) # 输出:[0.2 0.33333333 0.42857143 0.5 ]
print(a ** 2) # 输出:[ 1 4 9 16]

数组与标量运算

print(a + 10) # 输出:[11 12 13 14]
print(a * 2) # 输出:[2 4 6 8]
“`

5.2 数学函数

NumPy 提供了许多常用的数学函数,如三角函数、指数函数、对数函数等。这些函数也是按元素进行的。

“`python
arr = np.array([0, np.pi/2, np.pi])

print(np.sin(arr)) # 输出:[0.0000000e+00 1.0000000e+00 1.2246468e-16]
print(np.cos(arr)) # 输出:[ 1.000000e+00 6.123234e-17 -1.000000e+00]
print(np.exp(arr)) # 输出:[ 1. 4.81047738 23.14069263]
print(np.log(arr[1:])) # 输出:[ nan 1.14472989] (注意:log(0) 是未定义的)
“`

5.3 统计函数

NumPy 提供了丰富的统计函数,可以方便地计算数组的均值、方差、标准差、最大值、最小值等。

“`python
arr = np.array([1, 2, 3, 4, 5, 6])

print(np.mean(arr)) # 输出:3.5 (平均值)
print(np.median(arr)) # 输出:3.5 (中位数)
print(np.std(arr)) # 输出:1.707825127659933 (标准差)
print(np.var(arr)) # 输出:2.9166666666666665 (方差)
print(np.max(arr)) # 输出:6 (最大值)
print(np.min(arr)) # 输出:1 (最小值)
print(np.sum(arr)) # 输出:21 (总和)
print(np.prod(arr)) # 输出:720 (乘积)
print(np.cumsum(arr)) # 输出:[ 1 3 6 10 15 21] (累积和)
print(np.cumprod(arr)) # 输出:[ 1 2 6 24 120 720] (累积积)

沿着指定轴计算

arr2 = np.array([[1,2,3], [4,5,6]])
print(np.sum(arr2, axis=0)) # [5 7 9], 沿着列求和(axis=0)
print(np.sum(arr2, axis=1)) # [ 6 15], 沿着行求和(axis=1)
“`

5.4 线性代数运算

NumPy 提供了强大的线性代数运算功能,包括矩阵乘法、转置、求逆、求解线性方程组等。

“`python
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])

矩阵乘法

print(np.dot(a, b)) # 或 a @ b

输出:

[[19 22]

[43 50]]

矩阵转置

print(a.T)

输出:

[[1 3]

[2 4]]

矩阵求逆

a_inv = np.linalg.inv(a)
print(a_inv)

输出:

[[-2. 1. ]

[ 1.5 -0.5]]

求解线性方程组 ax = b

b = np.array([5, 11])
x = np.linalg.solve(a, b)
print(x) # 输出:[1. 2.]

计算行列式

print(np.linalg.det(a)) # -2.0

计算特征值和特征向量

eigenvalues, eigenvectors = np.linalg.eig(a)
print(“特征值:”, eigenvalues) # 特征值: [-0.37228132 5.37228132]
print(“特征向量:”, eigenvectors)

计算矩阵的秩

print(np.linalg.matrix_rank(a)) # 2

计算奇异值分解

U, S, V = np.linalg.svd(a)
print(“U:”, U)
print(“S:”, S)
print(“V:”, V)
“`

6. 数组形状操作

NumPy 提供了改变数组形状的函数,可以在不改变数据的情况下重新组织数组。

6.1 reshape()

reshape() 方法可以将数组转换为指定的形状。新的形状必须与原数组的元素总数兼容。

“`python
arr = np.arange(12)
print(arr) # [ 0 1 2 3 4 5 6 7 8 9 10 11]

转换为3×4的二维数组

new_arr = arr.reshape(3, 4)
print(new_arr)

[[ 0 1 2 3]

[ 4 5 6 7]

[ 8 9 10 11]]

使用 -1 自动计算维度

new_arr2 = arr.reshape(2, -1) # -1 表示该维度的大小由其他维度自动计算
print(new_arr2)

[[ 0 1 2 3 4 5]

[ 6 7 8 9 10 11]]

“`

6.2 ravel() 和 flatten()

ravel()flatten() 方法都可以将多维数组展平为一维数组。

  • ravel() 返回一个视图(view),如果修改了视图,原始数组也会被修改。
  • flatten() 返回一个副本(copy),修改副本不会影响原始数组。

“`python
arr = np.array([[1, 2, 3], [4, 5, 6]])

ravel_arr = arr.ravel()
flatten_arr = arr.flatten()

print(ravel_arr) # [1 2 3 4 5 6]
print(flatten_arr) # [1 2 3 4 5 6]

修改 ravel_arr 会影响原始数组

ravel_arr[0] = 10
print(arr)

[[10 2 3]

[ 4 5 6]]

修改 flatten_arr 不会影响原始数组

flatten_arr[0] = 20
print(arr) # 仍然是 [[10 2 3] [ 4 5 6]]
“`

6.3 transpose() 和 swapaxes()

transpose() 方法可以对数组进行转置(交换行和列)。swapaxes() 方法可以交换指定的两个轴。

“`python
arr = np.array([[1, 2, 3], [4, 5, 6]])

转置

transposed_arr = arr.transpose() # 或 arr.T
print(transposed_arr)

[[1 4]

[2 5]

[3 6]]

交换轴

swapped_arr = arr.swapaxes(0, 1)
print(swapped_arr) # 结果与转置相同

[[1 4]

[2 5]

[3 6]]

“`

7. 数组拼接和分割

NumPy 提供了多个函数用于数组的拼接和分割。

7.1 concatenate()

concatenate() 函数可以沿着指定的轴拼接多个数组。

“`python
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])

沿着行拼接(axis=0,默认值)

c = np.concatenate((a, b), axis=0)
print(c)

[[1 2]

[3 4]

[5 6]]

沿着列拼接(axis=1)

d = np.concatenate((a, b.T), axis=1) # 注意:b需要转置
print(d)

[[1 2 5]

[3 4 6]]

“`

7.2 stack(), hstack(), vstack()

  • stack():沿着新的轴堆叠数组。
  • hstack():水平堆叠数组(沿着列)。
  • vstack():垂直堆叠数组(沿着行)。

“`python
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

沿着新的轴堆叠

c = np.stack((a, b))
print(c)

[[1 2 3]

[4 5 6]]

水平堆叠

d = np.hstack((a, b))
print(d) # [1 2 3 4 5 6]

垂直堆叠

e = np.vstack((a, b))
print(e)

[[1 2 3]

[4 5 6]]

“`

7.3 split(), hsplit(), vsplit()

  • split():将数组沿着指定的轴分割成多个子数组。
  • hsplit():将数组水平分割(沿着列)。
  • vsplit():将数组垂直分割(沿着行)。

“`python
arr = np.arange(12).reshape(3, 4)

沿着行分割

split_arr = np.split(arr, 3, axis=0)
print(split_arr) # 分割成3个子数组

水平分割

hsplit_arr = np.hsplit(arr, 2) # 分割成2个子数组
print(hsplit_arr)

垂直分割

vsplit_arr = np.vsplit(arr, 3) # 分割成3个子数组
print(vsplit_arr)
“`

8. 广播(Broadcasting)

广播是 NumPy 中一种强大的机制,它允许不同形状的数组之间进行算术运算。广播的规则如下:

  1. 如果两个数组的维度不同,那么维度较小的数组的形状会在其左侧补 1,直到维度相同。
  2. 如果两个数组在某个维度上的大小相同,或者其中一个数组在该维度上的大小为 1,那么这两个数组在该维度上是兼容的。
  3. 如果两个数组在所有维度上都是兼容的,那么它们可以一起广播。
  4. 广播会在缺失或大小为 1 的维度上进行。

“`python
a = np.array([[1, 2, 3], [4, 5, 6]]) # 形状:(2, 3)
b = np.array([10, 20, 30]) # 形状:(3,)

a + b 可以进行广播

c = a + b
print(c)

[[11 22 33]

[14 25 36]]

广播过程:

1. b 的形状变为 (1, 3)

2. b 在第0维上复制,变为 [[10 20 30], [10 20 30]]

3. a 和 b 按元素相加

“`

广播使得代码更简洁、更高效,避免了不必要的循环。

9. 通用函数(ufunc)

NumPy 的通用函数(universal functions,简称 ufunc)是一种对 ndarray 进行逐元素操作的函数。ufunc 有以下特点:

  • 逐元素操作: ufunc 会对数组中的每个元素进行相同的操作。
  • 向量化: ufunc 是向量化的,这意味着它们可以避免显式的循环,从而提高性能。
  • 广播: ufunc 支持广播机制。

NumPy 提供了大量的 ufunc,涵盖了各种数学、统计、逻辑、位运算等操作。前面介绍的许多函数(如 sin()cos()exp()mean()std() 等)都是 ufunc。

除了内置的 ufunc,你还可以使用 np.frompyfunc() 创建自定义的 ufunc。

10. 进阶主题

本教程涵盖了 NumPy 的基础知识,但 NumPy 的功能远不止于此。以下是一些进阶主题,供你进一步学习:

  • 结构化数组(Structured Arrays): 允许数组中的每个元素包含多个字段,每个字段可以有不同的数据类型。
  • 内存映射数组(Memory-Mapped Arrays): 允许你处理非常大的数组,而无需将整个数组加载到内存中。
  • 高级索引: 使用花式索引(fancy indexing)和掩码(masking)进行更复杂的数组操作。
  • 线性代数: 深入了解 NumPy 的线性代数模块(numpy.linalg)。
  • 傅里叶变换: 使用 NumPy 的傅里叶变换模块(numpy.fft)进行信号处理。
  • 随机数生成: 深入了解 NumPy 的随机数模块(numpy.random),包括各种概率分布的随机数生成。

结语

NumPy 是 Python 数据分析和科学计算的基石。掌握 NumPy 的基础知识对于高效地进行数据处理和分析至关重要。本教程介绍了 NumPy 的核心概念、基本操作以及一些进阶主题,希望能够帮助你快速入门 NumPy。

要熟练掌握 NumPy,最好的方法是多练习、多实践。建议你结合实际的数据分析项目,不断地使用 NumPy 来解决问题,这样才能更好地理解和掌握 NumPy 的强大功能。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部