NumPy 基础
NumPy(Numerical Python)是 Python 数据分析的基础库,提供了高性能的多维数组对象和用于处理这些数组的工具。本章将详细介绍 NumPy 的核心概念和使用方法。
为什么需要 NumPy?
传统 Python 列表的局限性
# Python 列表 - 存储整数
numbers = [1, 2, 3, 4, 5]
# 对每个元素加1 - 需要循环
result = []
for n in numbers:
result.append(n + 1)
# 或者使用列表推导式
result = [n + 1 for n in numbers]
NumPy 的优势
import numpy as np
# 创建 NumPy 数组
arr = np.array([1, 2, 3, 4, 5])
# 向量化操作 - 直接加1
result = arr + 1 # [2, 3, 4, 5, 6]
# 性能对比
import time
# Python 列表
start = time.time()
numbers = list(range(1000000))
result = [n + 1 for n in numbers]
print(f"Python 列表: {time.time() - start:.4f}秒")
# NumPy 数组
start = time.time()
arr = np.arange(1000000)
result = arr + 1
print(f"NumPy 数组: {time.time() - start:.4f}秒")
NumPy 比纯 Python 快 10-100 倍!
创建数组
从列表创建
import numpy as np
# 一维数组
arr1d = np.array([1, 2, 3, 4, 5])
print(arr1d)
# 输出: [1 2 3 4 5]
# 二维数组
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2d)
# 输出:
# [[1 2 3]
# [4 5 6]]
# 指定数据类型
arr_int = np.array([1, 2, 3], dtype=np.int32)
arr_float = np.array([1.0, 2.0, 3.0], dtype=np.float64)
使用内置函数创建
# arange - 类似于 range
arr = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
arr = np.arange(0, 10, 2) # [0 2 4 6 8]
# linspace - 创建等间距数组
arr = np.linspace(0, 10, 5) # [ 0. 2.5 5. 7.5 10. ]
# zeros - 全零数组
arr = np.zeros(5) # [0. 0. 0. 0. 0.]
arr = np.zeros((3, 4)) # 3x4 全零矩阵
# ones - 全一数组
arr = np.ones(5) # [1. 1. 1. 1. 1.]
# full - 指定值的数组
arr = np.full(5, 7) # [7 7 7 7 7]
arr = np.full((3, 3), -1) # 3x3 全 -1 矩阵
# eye - 单位矩阵
arr = np.eye(3) # 3x3 单位矩阵
# random - 随机数组
arr = np.random.rand(5) # [0, 1) 均匀分布
arr = np.random.randn(5) # 标准正态分布
arr = np.random.randint(0, 10, 5) # [0, 10) 整数随机
数组属性
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
print(arr.itemsize) # 每个元素字节数: 8
print(arr.nbytes) # 总字节数: 48
数组索引和切片
基本索引
arr = np.array([1, 2, 3, 4, 5])
# 单个索引
print(arr[0]) # 第一个元素: 1
print(arr[-1]) # 最后一个元素: 5
# 切片
print(arr[1:4]) # [2 3 4]
print(arr[:3]) # [1 2 3]
print(arr[::2]) # [1 3 5] - 步长为2
# 多维数组索引
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2d[0]) # 第一行: [1 2 3]
print(arr2d[0, 0]) # 第一个元素: 1
print(arr2d[1:, :2]) # 行索引1及以后,列索引0-1
高级索引
# 整数数组索引 - 使用索引数组选择元素
arr = np.array([10, 20, 30, 40, 50])
indices = [0, 2, 4]
print(arr[indices]) # [10 30 50]
# 布尔索引 - 使用布尔数组选择元素
arr = np.array([1, 2, 3, 4, 5])
mask = arr > 3
print(arr[mask]) # [4 5]
print(arr[arr % 2 == 0]) # [2 4] - 选择偶数
数组运算
算术运算
arr = np.array([1, 2, 3, 4, 5])
# 基本运算
print(arr + 1) # [2 3 4 5 6]
print(arr - 1) # [0 1 2 3 4]
print(arr * 2) # [2 4 6 8 10]
print(arr / 2) # [0.5 1. 1.5 2. 2.5]
print(arr ** 2) # [ 1 4 9 16 25]
print(arr % 2) # [1 0 1 0 1]
# 数组之间的运算
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(a + b) # [5 7 9]
print(a * b) # [ 4 10 18]
聚合函数
arr = np.array([1, 2, 3, 4, 5])
# 统计函数
print(arr.sum()) # 求和: 15
print(arr.mean()) # 平均值: 3.0
print(arr.std()) # 标准差: 1.41421356
print(arr.var()) # 方差: 2.0
print(arr.min()) # 最小值: 1
print(arr.max()) # 最大值: 5
# 找到最大值/最小值的索引
print(arr.argmin()) # 0
print(arr.argmax()) # 4
# 多维数组的聚合
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2d.sum()) # 所有元素求和: 21
print(arr2d.sum(axis=0)) # 按列求和: [5 7 9]
print(arr2d.sum(axis=1)) # 按行求和: [6 15]
广播机制
广播允许不同形状的数组进行运算:
# 标量和数组运算
arr = np.array([1, 2, 3])
result = arr + 5 # [6 7 8] - 5 被广播到数组形状
# 一维和二维数组运算
a = np.array([[1], [2], [3]]) # 形状 (3, 1)
b = np.array([1, 2, 3]) # 形状 (3,)
# 结果形状 (3, 3)
# [[2 3 4]
# [3 4 5]
# [4 5 6]]
数组操作
改变形状
arr = np.arange(12)
print(arr.reshape(3, 4)) # 3x4 矩阵
print(arr.reshape(2, -1)) # 自动计算列数: 2x6
# flatten 和 ravel - 展平数组
arr2d = np.array([[1, 2], [3, 4]])
print(arr2d.flatten()) # [1 2 3 4] - 返回副本
print(arr2d.ravel()) # [1 2 3 4] - 返回视图(如果可能)
# transpose - 转置
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2d.T) # [[1 4], [2 5], [3 6]]
数组拼接
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# concatenate - 拼接
print(np.concatenate([a, b])) # [1 2 3 4 5 6]
# vstack - 垂直堆叠
print(np.vstack([a, b])) # [[1 2 3]
# [4 5 6]]
# hstack - 水平堆叠
print(np.hstack([a, b])) # [1 2 3 4 5 6]
数组分割
arr = np.arange(12)
# split - 分割
print(np.split(arr, 3)) # 分成3份: [0 1 2 3], [4 5 6 7], [8 9 10 11]
print(np.split(arr, [3, 7])) # 在索引3和7处分割: [0 1 2], [3 4 5 6], [7 8 9 10 11]
arr2d = np.arange(16).reshape(4, 4)
# hsplit - 水平分割
print(np.hsplit(arr2d, 2)) # 分成2个4x2矩阵
# vsplit - 垂直分割
print(np.vsplit(arr2d, 2)) # 分成2个2x4矩阵
条件运算
where 函数
# np.where(condition, x, y) - 条件选择
arr = np.array([1, 2, 3, 4, 5])
result = np.where(arr > 3, arr, 0)
print(result) # [0 0 0 4 5]
# 只提供条件,返回索引
indices = np.where(arr > 3)
print(indices) # (array([3, 4]),)
逻辑函数
arr = np.array([1, 2, 3, 4, 5])
print(np.any(arr > 3)) # True - 任意元素满足
print(np.all(arr > 0)) # True - 所有元素满足
print(np.logical_and(arr > 1, arr < 5)) # [False True True True False]
print(np.logical_not(arr)) # [-2 -3 -4 -5 -6]
实践示例
示例:计算股票收益率
# 模拟股票价格数据
prices = np.array([100, 102, 101, 105, 107, 106, 110, 108, 112, 115])
# 计算日收益率
daily_returns = (prices[1:] - prices[:-1]) / prices[:-1]
print("日收益率:", daily_returns)
# 计算统计指标
print("平均收益率:", np.mean(daily_returns))
print("收益率标准差:", np.std(daily_returns))
print("最大收益率:", np.max(daily_returns))
print("最小收益率:", np.min(daily_returns))
# 计算累计收益
cumulative_returns = (prices / prices[0]) - 1
print("累计收益:", cumulative_returns)
示例:图像处理基础
# 创建一个简单的图像矩阵(灰度图像)
# 使用随机值模拟噪点图像
image = np.random.randint(0, 256, (100, 100), dtype=np.uint8)
# 调整亮度 - 所有像素值增加50
brightened = np.clip(image + 50, 0, 255).astype(np.uint8)
# 创建对比度增强
mean_value = np.mean(image)
contrasted = np.clip((image - mean_value) * 1.5 + mean_value, 0, 255).astype(np.uint8)
# 提取红色通道(模拟RGB图像)
# 假设有一个RGB图像
rgb_image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
red_channel = rgb_image[:, :, 0]
green_channel = rgb_image[:, :, 1]
blue_channel = rgb_image[:, :, 2]
小结
本章我们学习了:
- NumPy 的优势:向量化操作,高性能计算
- 创建数组:从列表创建、内置函数创建
- 数组属性:维度、形状、数据类型
- 索引和切片:基本索引、高级索引、布尔索引
- 数组运算:算术运算、聚合函数、广播机制
- 数组操作:形状改变、拼接、分割
- 条件运算:where 函数、逻辑函数
练习
- 创建一个 5x5 的随机整数数组(1-100)
- 计算数组中所有偶数的平均值
- 将数组中所有大于50的值替换为100
- 创建一个 3x4 的数组,计算每行每列的和
- 使用布尔索引找出数组中所有在 20-80 范围内的值
下一步
现在你已经掌握了 NumPy 的基础,接下来让我们学习 Pandas 基础,这是数据分析的核心工具!