跳到主要内容

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]

小结

本章我们学习了:

  1. NumPy 的优势:向量化操作,高性能计算
  2. 创建数组:从列表创建、内置函数创建
  3. 数组属性:维度、形状、数据类型
  4. 索引和切片:基本索引、高级索引、布尔索引
  5. 数组运算:算术运算、聚合函数、广播机制
  6. 数组操作:形状改变、拼接、分割
  7. 条件运算:where 函数、逻辑函数

练习

  1. 创建一个 5x5 的随机整数数组(1-100)
  2. 计算数组中所有偶数的平均值
  3. 将数组中所有大于50的值替换为100
  4. 创建一个 3x4 的数组,计算每行每列的和
  5. 使用布尔索引找出数组中所有在 20-80 范围内的值

下一步

现在你已经掌握了 NumPy 的基础,接下来让我们学习 Pandas 基础,这是数据分析的核心工具!