数据分析
info
数据分析是从数据中提取有价值信息的过程。Python 的数据分析生态系统以三大核心库为基础:
- NumPy:提供高性能的多维数组对象和数学运算能力
- Pandas:提供灵活的数据结构(DataFrame/Series)和数据操作工具
- Matplotlib/Pyecharts:提供强大的数据可视化能力
这三个库相互配合,构成了 Python 数据分析的完整工作流:数据处理 → 数据分析 → 数据可视化。
import numpy as np # 数值计算
import pandas as pd # 数据处理
import matplotlib.pyplot as plt # 数据可视化
NumPy
NumPy(Numerical Python)是 Python 科学计算的基础库。它提供了高性能的多维数组对象(ndarray)和用于处理这些数 组的工具。
NumPy 的核心优势:
- 高效的数组运算:底层用 C 实现,比 Python 列表快 10-100 倍
- 广播机制:不同形状的数组也能进行运算
- 丰富的数学函数:线性代数、傅里叶变换、随机数生成等
- 生态系统基石:Pandas、SciPy、Scikit-learn 等都基于 NumPy
基础入门
导入和创建数组
# 推荐的导入方式
import numpy as np
# 其他导入方式(不推荐)
import numpy # 需要写 numpy.array,太长
from numpy import * # 污染命名空间
from numpy import array, sin # 只导入部分函数
tip
推荐使用 import numpy as np
,这是 NumPy 官方文档和社区的标准约定。
为什么使用 NumPy 而不是 Python 列表?
# Python 列表的局限性
a = [1, 2, 3]
# a + 1 # TypeError: 列表不支持与整数相加
# 需要使用列表推导式
b = [x + 1 for x in a]
print(b) # [2, 3, 4]
# NumPy 数组支持向量化运算
import numpy as np
a = np.array([1, 2, 3])
b = a + 1
print(b) # [2 3 4]
# 数组间的运算(对应元素)
c = a + b
print(c) # [3 5 7]
# 对应元素相乘
print(a * b) # [2 6 12]
# 对应元素乘方
print(a ** b) # [1 8 81]
tip
NumPy 的性能优势:
# Python 列表:需要循环
result = []
for i in range(1000000):
result.append(i * 2)
# NumPy:向量化运算,快 10-100 倍
arr = np.arange(1000000)
result = arr * 2
数组属性
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a)
# [[1 2 3]
# [4 5 6]]
# 查看形状(返回元组,每个元素代表该维度的元素数目)
print(a.shape) # (2, 3) - 2行3列
# 查看总元素数
print(a.size) # 6
# 查看维度
print(a.ndim) # 2
# 查看数据类型
print(a.dtype) # int64 或 int32
# 查看每个元素的字节大小
print(a.itemsize) # 8 (64位整数)
tip
常用属性速查:
shape
:数组形状,如 (3, 4) 表示3行4列size
:总元素个数ndim
:维度数(1维、2维、3维...)dtype
:数据类型(int64, float64等)itemsize
:每个元素占用的字节数
创建数组的多种方式
import numpy as np
# 从列表创建
a = np.array([1, 2, 3, 4])
print(a) # [1 2 3 4]
# 从元组创建
b = np.array((1, 2, 3, 4))
print(b) # [1 2 3 4]
# 创建二维数组
c = np.array([[1, 2], [3, 4]])
print(c)
# [[1 2]
# [3 4]]
# 指定数据类型
d = np.array([1, 2, 3], dtype=float)
print(d) # [1. 2. 3.]
# 创建全零数组
zeros = np.zeros((2, 3))
print(zeros)
# [[0. 0. 0.]
# [0. 0. 0.]]
# 创建全一数组
ones = np.ones((2, 3))
print(ones)
# [[1. 1. 1.]
# [1. 1. 1.]]
# 创建单位矩阵
eye = np.eye(3)
print(eye)
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
# 创建指定值的数组
full = np.full((2, 3), 7)
print(full)
# [[7 7 7]
# [7 7 7]]
数组索引和切片
一维数组索引
import numpy as np
a = np.array([1, 2, 3, 4, 5])
# 基本索引
print(a[0]) # 1 - 第一个元素
print(a[-1]) # 5 - 最后一个元素
# 切片(左闭右开)
print(a[:2]) # [1 2] - 前两个元素
print(a[2:]) # [3 4 5] - 从第3个到最后
print(a[1:4]) # [2 3 4] - 第2到第4个
print(a[::2]) # [1 3 5] - 步长为2
print(a[::-1]) # [5 4 3 2 1] - 反转
# 修改元素
a[0] = 100
print(a) # [100 2 3 4 5]
多维数组索引
import numpy as np
a = np.array([[0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55]])
# 访问单个元素
print(a[0, 3]) # 3 - 第0行第3列
# 访问整行
print(a[0]) # [ 0 1 2 3 4 5]
# 访问整列
print(a[:, 2]) # [ 2 12 22 32 42 52]
# 行切片
print(a[0:2]) # 前两行
# [[ 0 1 2 3 4 5]
# [10 11 12 13 14 15]]
# 列切片
print(a[:, 3:5]) # 所有行的第3-4列
# [[ 3 4]
# [13 14]
# [23 24]
# [33 34]
# [43 44]
# [53 54]]
# 组合切片
print(a[0, 3:5]) # 第0行的第3-4列 [3 4]
print(a[4:, 4:]) # 最后两行的最后两列
# [[44 45]
# [54 55]]
# 步长切片
print(a[2::2, ::2]) # 从第2行开始每隔一行,每隔一列
# [[20 22 24]
# [40 42 44]]
warning
切片与引用: NumPy 数组的切片是引用,不是复制!修改切片会影响原数组。
a = np.array([1, 2, 3, 4, 5])
b = a[2:4] # b 是 a 的视图
b[0] = 100 # 修改 b
print(a) # [ 1 2 100 4 5] - a 也被修改了!
# 使用 copy() 创建副本
c = a[2:4].copy()
c[0] = 200
print(a) # [ 1 2 100 4 5] - a 不受影响
花式索引
使用数组或列表作为索引:
import numpy as np
a = np.arange(0, 80, 10) # [ 0 10 20 30 40 50 60 70]
# 使用索引数组
indices = [1, 2, -3]
print(a[indices]) # [10 20 50]
# 使用索引列表
print(a[[0, 2, 4]]) # [ 0 20 40]
# 多维数组的花式索引
a = np.arange(12).reshape(3, 4)
print(a)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# 选择第0行和第2行
print(a[[0, 2]])
# [[ 0 1 2 3]
# [ 8 9 10 11]]
# 选择特定的行列组合
rows = [0, 1, 2]
cols = [1, 2, 3]
print(a[rows, cols]) # [ 1 6 11]
布尔索引
使用布尔数组进行条件筛选:
import numpy as np
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
# 创建布尔mask
mask = a > 5
print(mask)
# [False False False False False True True True True True]
# 使用布尔索引
print(a[mask]) # [ 6 7 8 9 10]
# 直接使用条件
print(a[a > 5]) # [ 6 7 8 9 10]
print(a[a % 2 == 0]) # [ 2 4 6 8 10] - 偶数
# 组合条件
print(a[(a > 3) & (a < 8)]) # [4 5 6 7]
print(a[(a < 3) | (a > 8)]) # [ 1 2 9 10]
# 修改满足条件的元素
a[a > 5] = 0
print(a) # [1 2 3 4 5 0 0 0 0 0]
tip
布尔运算符:
&
:与(and)|
:或(or)~
:非(not)
注意要使用 &
和 |
,而不是 and
和 or
,并且需要用括号!
where 函数
where
函数返回满足条件的元素索引:
import numpy as np
a = np.array([1, 2, 4, 6, 8])
# 查找满足条件的索引
indices = np.where(a > 2)
print(indices) # (array([2, 3, 4]),)
print(indices[0]) # [2 3 4]
# 使用索引取值
print(a[indices]) # [4 6 8]
# 二维数组的 where
a = np.array([[0, 12, 5, 20],
[1, 2, 11, 15]])
rows, cols = np.where(a > 10)
print(rows) # [0 0 1 1]
print(cols) # [1 3 2 3]
print(a[rows, cols]) # [12 20 11 15]
# where 的三元运算用法
a = np.array([1, 2, 3, 4, 5])
result = np.where(a > 3, '大', '小')
print(result) # ['小' '小' '小' '大' '大']
数组运算
基本数学运算
import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
# 加法
print(a + b) # [11 22 33 44]
print(a + 10) # [11 12 13 14] - 广播
# 减法
print(b - a) # [ 9 18 27 36]
print(a - 1) # [0 1 2 3]
# 乘法(对应元素)
print(a * b) # [ 10 40 90 160]
print(a * 2) # [2 4 6 8]
# 除法
print(b / a) # [10. 10. 10. 10.]
print(a / 2) # [0.5 1. 1.5 2. ]
# 整除
print(b // a) # [10 10 10 10]
# 求余
print(b % a) # [0 0 0 0]
# 幂运算
print(a ** 2) # [ 1 4 9 16]
print(2 ** a) # [ 2 4 8 16]
广播机制
广播(Broadcasting)允许不同形状的数组进行运算:
import numpy as np
# 一维和标量
a = np.array([1, 2, 3])
print(a + 10) # [11 12 13]
# 二维和一维
a = np.array([[1, 2, 3],
[4, 5, 6]])
b = np.array([10, 20, 30])
print(a + b)
# [[11 22 33]
# [14 25 36]]
# 二维和列向量
a = np.array([[1, 2, 3],
[4, 5, 6]])
b = np.array([[10],
[20]])
print(a + b)
# [[11 12 13]
# [24 25 26]]
# 理解 广播规则
# 规则1:如果两个数组维度不同,较小维度数组会在前面补1
# 规则2:如果某个维度大小不同,大小为1的会被"拉伸"以匹配另一个
tip
广播规则简记:
- 如果两个数组形状在某个维度上一致或其中一个为1,则兼容
- 维度数较小的数组会在前面补1
- 输出形状是每个维度的最大值
a: (3, 4) b: (4,) -> (3, 4)
a: (3, 1) b: (3, 4) -> (3, 4)
a: (2, 3, 4) b: (3, 1) -> (2, 3, 4)
通用函数(ufunc)
import numpy as np
a = np.array([1, 4, 9, 16])
# 数学函数
print(np.sqrt(a)) # [1. 2. 3. 4.] - 平方根
print(np.square(a)) # [ 1 16 81 256] - 平方
print(np.exp(a)) # [2.71828183e+00 5.45981500e+01 ...]
print(np.log(a)) # [0. 1.38629436 2.19722458 2.77258872]
print(np.log10(a)) # [0. 0.60205999 0.95424251 1.20411998]
# 三角函数
angles = np.array([0, np.pi/2, np.pi])
print(np.sin(angles)) # [ 0.0000000e+00 1.0000000e+00 1.2246468e-16]
print(np.cos(angles)) # [ 1.000000e+00 6.123234e-17 -1.000000e+00]
print(np.tan(angles)) # [ 0.00000000e+00 1.63312394e+16 -1.22464680e-16]
# 取整函数
a = np.array([1.2, 2.5, 3.7, 4.9])
print(np.floor(a)) # [1. 2. 3. 4.] - 向下取整
print(np.ceil(a)) # [2. 3. 4. 5.] - 向上取整
print(np.round(a)) # [1. 2. 4. 5.] - 四舍五入
# 绝对值
a = np.array([-1, -2, 3, -4])
print(np.abs(a)) # [1 2 3 4]
print(np.absolute(a)) # [1 2 3 4] - 同上
# 符号函数
print(np.sign(a)) # [-1 -1 1 -1]
聚合函数
import numpy as np
a = np.array([[1, 2, 3],
[4, 5, 6]])
# 求和
print(np.sum(a)) # 21 - 所有元素求和
print(a.sum()) # 21 - 同上
print(a.sum(axis=0)) # [5 7 9] - 按列求和
print(a.sum(axis=1)) # [ 6 15] - 按行求和
# 平均值
print(np.mean(a)) # 3.5
print(a.mean(axis=0)) # [2.5 3.5 4.5]
print(a.mean(axis=1)) # [2. 5.]
# 最大最小值
print(a.max()) # 6
print(a.min()) # 1
print(a.max(axis=0)) # [4 5 6]
print(a.min(axis=1)) # [1 4]
# 最大最小值的索引
print(a.argmax()) # 5 - 扁平化后的索引
print(a.argmin()) # 0
print(a.argmax(axis=0)) # [1 1 1]
print(a.argmax(axis=1)) # [2 2]
# 标准差和方差
print(a.std()) # 1.707825127659933
print(a.var()) # 2.9166666666666665
# 累积和和累积积
print(np.cumsum(a)) # [ 1 3 6 10 15 21]
print(np.cumprod(a)) # [ 1 2 6 24 120 720]
tip
axis 参数理解:
axis=None
:对所有元素操作(默认)axis=0
:沿着第0维(列),对每列操作axis=1
:沿着第1维(行),对每行操作
记忆技巧:axis=0 会让该维度"消失",结果是剩余维度的结果
条件筛选
import numpy as np
a = np.array([1, 2, 3, 4, 5, 6])
# clip:限制在范围内
print(np.clip(a, 2, 5)) # [2 2 3 4 5 5]
# 判断函数
print(np.all(a > 0)) # True - 是否全部满足
print(np.any(a > 5)) # True - 是否有任意元素满足
# 最大最小值比较
a = np.array([1, 5, 3])
b = np.array([2, 4, 6])
print(np.maximum(a, b)) # [2 5 6] - 逐元素取最大
print(np.minimum(a, b)) # [1 4 3] - 逐元素取最小
数组操作
形状操作
import numpy as np
a = np.arange(12)
print(a) # [ 0 1 2 3 4 5 6 7 8 9 10 11]
print(a.shape) # (12,)
# reshape:改变形状(不改变原数组)
b = a.reshape(3, 4)
print(b)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(a.shape) # (12,) - 原数组未改变
# resize:改变形状(改变原数组)
a.resize(3, 4)
print(a.shape) # (3, 4) - 原数组已改变
# reshape 的 -1 参数(自动计算)
a = np.arange(12)
print(a.reshape(3, -1)) # (3, 4) - 自动计算为4
print(a.reshape(-1, 4)) # (3, 4) - 自动计算为3
print(a.reshape(2, 2, -1)) # (2, 2, 3)
# flatten:展平为一维(复制)
a = np.array([[1, 2], [3, 4]])
b = a.flatten()
b[0] = 100
print(a[0, 0]) # 1 - 原数组未改变
# ravel:展平为一维(视图)
b = a.ravel()
b[0] = 100
print(a[0, 0]) # 100 - 原数组被改变
# 转置
a = np.array([[1, 2, 3],
[4, 5, 6]])
print(a.T)
# [[1 4]
# [2 5]
# [3 6]]
# squeeze:去除长度为1的维度
a = np.arange(10).reshape(1, 10)
print(a.shape) # (1, 10)
b = np.squeeze(a)
print(b.shape) # (10,)
# expand_dims:增加维度
a = np.array([1, 2, 3])
b = np.expand_dims(a, axis=0)
print(b.shape) # (1, 3)
c = np.expand_dims(a, axis=1)
print(c.shape) # (3, 1)
warning
reshape vs resize vs ravel vs flatten:
reshape
:返回新视图,不改变原数组resize
:直接修改原数组ravel
:返回展平的视图(可能影响原数组)flatten
:返回展平的副本(不影响原数组)
a = np.array([[1, 2], [3, 4]])
b = a.reshape(4) # 新视图
c = a.ravel() # 展平视图
d = a.flatten() # 展平副本
c[0] = 100
print(a[0, 0]) # 100 - ravel 影响原数组
d[0] = 200
print(a[0, 0]) # 100 - flatten 不影响原数组
数组合并
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
# concatenate:沿指定轴连接
print(np.concatenate([a, b], axis=0)) # 垂直拼接
# [[1 2]
# [3 4]
# [5 6]
# [7 8]]
print(np.concatenate([a, b], axis=1)) # 水平拼接
# [[1 2 5 6]
# [3 4 7 8]]
# vstack:垂直堆叠(相当于 axis=0)
print(np.vstack([a, b]))
# [[1 2]
# [3 4]
# [5 6]
# [7 8]]
# hstack:水平堆叠(相当于 axis=1)
print(np.hstack([a, b]))
# [[1 2 5 6]
# [3 4 7 8]]
# stack:沿新轴堆叠
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(np.stack([a, b])) # axis=0(默认)
# [[1 2 3]
# [4 5 6]]
print(np.stack([a, b], axis=1)) # axis=1
# [[1 4]
# [2 5]
# [3 6]]
# append:追加元素(返回新数组)
a = np.array([1, 2, 3])
b = np.append(a, [4, 5, 6])
print(b) # [1 2 3 4 5 6]
# 二维数组的 append
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
print(np.append(a, b, axis=0))
# [[1 2]
# [3 4]
# [5 6]]
tip
数组合并方法选择:
- 垂直拼接(增加行):
vstack
或concatenate(axis=0)
- 水平拼接(增加列):
hstack
或concatenate(axis=1)
- 新维度堆叠:
stack
- 简单追加:
append
(但效率较低)
数组分割
import numpy as np
a = np.arange(12).reshape(3, 4)
print(a)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# split:均等分割
parts = np.split(a, 3, axis=0) # 分成3部分
for i, part in enumerate(parts):
print(f"Part {i}:\n{part}")
# vsplit:垂直分割(按行)
parts = np.vsplit(a, 3) # 分成3行
# hsplit:水平分割(按列)
parts = np.hsplit(a, [1, 3]) # 在列1和列3处分割
# 结果:[:, :1], [:, 1:3], [:, 3:]
# array_split:不均等分割
a = np.arange(10)
parts = np.array_split(a, 3) # 分成3部分(不均等)
print(parts[0]) # [0 1 2 3]
print(parts[1]) # [4 5 6]
print(parts[2]) # [7 8 9]
数组复制
import numpy as np
a = np.array([1, 2, 3, 4])
# 赋值(共享内存)
b = a
b[0] = 100
print(a[0]) # 100 - a 被改变
# view(浅拷贝,共享数据)
a = np.array([1, 2, 3, 4])
b = a.view()
b[0] = 100
print(a[0]) # 100 - a 被改变
b.shape = (2, 2)
print(a.shape) # (4,) - 形状独立
# copy(深拷贝,独立数据)
a = np.array([1, 2, 3, 4])
b = a.copy()
b[0] = 100
print(a[0]) # 1 - a 不受影响
warning
三种复制方式的区别:
方式 | 内存 | 数据修改 | 形状修改 |
---|---|---|---|
b = a | 共享 | 互相影响 | 互相影响 |
b = a.view() | 共享 | 互相影响 | 不影响 |
b = a.copy() | 独立 | 不影响 | 不影响 |
建议:
- 只是引 用用赋值
- 需要不同形状但共享数据用 view
- 需要完全独立的副本用 copy
数组创建函数
NumPy 提供了多种便捷的数组创建函数。
序列生成
import numpy as np
# arange:类似 range,生成等差数列
print(np.arange(5)) # [0 1 2 3 4]
print(np.arange(2, 10)) # [2 3 4 5 6 7 8 9]
print(np.arange(0, 10, 2)) # [0 2 4 6 8]
print(np.arange(0, 1, 0.1)) # [0. 0.1 0.2 ... 0.9]
# linspace:生成指定数量的等差数列(包含终点)
print(np.linspace(0, 1, 5)) # [0. 0.25 0.5 0.75 1. ]
print(np.linspace(0, 10, 11)) # [ 0. 1. 2. ... 10.]
print(np.linspace(0, 2*np.pi, 5)) # [0. 1.57 3.14 4.71 6.28]
# logspace:生成对数等差数列
print(np.logspace(0, 2, 5)) # [ 1. 3.16 10. 31.62 100. ]
# 相当于 [10^0, 10^0.5, 10^1, 10^1.5, 10^2]
tip
arange vs linspace:
arange(start, stop, step)
:指定步长,不包含终点linspace(start, stop, num)
:指定数量,包含终点
# 生成0到10的数
arange(0, 10, 1) # [0 1 2 3 4 5 6 7 8 9] - 10个数
linspace(0, 10, 11) # [0 1 2 3 4 5 6 7 8 9 10] - 11个数
特殊数组
import numpy as np
# 零数组
print(np.zeros(5)) # [0. 0. 0. 0. 0.]
print(np.zeros((2, 3))) # 2x3 零矩阵
# 一数组
print(np.ones(5)) # [1. 1. 1. 1. 1.]
print(np.ones((2, 3))) # 2x3 一矩阵
# 指定值数组
print(np.full(5, 7)) # [7 7 7 7 7]
print(np.full((2, 3), 3.14)) # 2x3 矩阵,值都是3.14
# 单位矩阵
print(np.eye(3))
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
# 对角矩阵
print(np.diag([1, 2, 3]))
# [[1 0 0]
# [0 2 0]
# [0 0 3]]
# 空数组(未初始化)
print(np.empty((2, 3))) # 值是随机的(内存中的残留值)
# 类似现有数组的形状
a = np.array([[1, 2], [3, 4]])
print(np.zeros_like(a)) # 形状相同的零数组
print(np.ones_like(a)) # 形状相同的一数组
print(np.full_like(a, 7)) # 形状相同,值为7
随机数组
import numpy as np
# 设置随机种子(保证可重复性)
np.random.seed(42)
# 均匀分布 [0, 1)
print(np.random.rand(5)) # 一维
print(np.random.rand(2, 3)) # 二维
# 标准正态分布(均值0,标准差1)
print(np.random.randn(5)) # 一维
print(np.random.randn(2, 3)) # 二维
# 指定范围的整数
print(np.random.randint(0, 10, 5)) # [0, 10) 的5个整数
print(np.random.randint(1, 100, (2, 3))) # 2x3 矩阵
# 指定范围的均匀分布
print(np.random.uniform(0, 10, 5)) # [0, 10) 的均匀分布
# 正态分布(指定均值和标准差)
print(np.random.normal(5, 2, 10)) # 均值5,标准差2,10个数
# 从数组中随机选择
a = np.array([1, 2, 3, 4, 5])
print(np.random.choice(a, 3)) # 随机选3个(可重复)
print(np.random.choice(a, 3, replace=False)) # 不重复
# 打乱数组
np.random.shuffle(a) # 原地打乱
print(a)
# 随机排列
print(np.random.permutation(10)) # [0, 10) 的随机排列
tip
新版随机数生成(推荐):
NumPy 1.17+ 推荐使用 np.random.Generator
:
rng = np.random.default_rng(42) # 新式随机数生成器
rng.random(5) # 替代 rand
rng.standard_normal(5) # 替代 randn
rng.integers(0, 10, 5) # 替代 randint
rng.choice(a, 3) # 替代 choice
网格生成
import numpy as np
# meshgrid:生成网格坐标
x = np.linspace(-1, 1, 3) # [-1. 0. 1.]
y = np.linspace(-1, 1, 3) # [-1. 0. 1.]
X, Y = np.meshgrid(x, y)
print(X)
# [[-1. 0. 1.]
# [-1. 0. 1.]
# [-1. 0. 1.]]
print(Y)
# [[-1. -1. -1.]
# [ 0. 0. 0.]
# [ 1. 1. 1.]]
# 常用于3D绘图或计算
Z = np.sqrt(X**2 + Y**2) # 计算每个点到原点的距离
print(Z)
# [[1.41421356 1. 1.41421356]
# [1. 0. 1. ]
# [1.41421356 1. 1.41421356]]
数据IO
NumPy 支持多种文件格式的读写。
文本文件
import numpy as np
# 创建示例数据
data = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 保存为文本文件
np.savetxt('data.txt', data)
# 默认使用科学计数法:1.000000e+00 2.000000e+00 ...
# 指定格式
np.savetxt('data.txt', data, fmt='%d') # 整数格式
np.savetxt('data.txt', data, fmt='%.2f') # 保留2位小数
# 指定分隔符
np.savetxt('data.csv', data, delimiter=',', fmt='%d')
# 读取文本文件
loaded = np.loadtxt('data.txt')
print(loaded)
# 读取CSV
loaded = np.loadtxt('data.csv', delimiter=',')
print(loaded)
# genfromtxt:更强大的文本读取(可处理缺失值)
data_with_header = """
Name,Age,Score
Alice,25,85.5
Bob,30,92.0
Charlie,28,78.5
"""
# 保存到文件
with open('students.csv', 'w') as f:
f.write(data_with_header)
# 读取(跳过标题行)
data = np.genfromtxt('students.csv',
delimiter=',',
skip_header=1,
usecols=(1, 2), # 只读取年龄和分数
dtype=float)
print(data)
# [[25. 85.5]
# [30. 92. ]
# [28. 78.5]]
tip
loadtxt vs genfromtxt:
loadtxt
:快速,适合简单规整的数据genfromtxt
:功能强大,可处理缺失值、注释、复杂格式
常用参数:
delimiter
:分隔符(默认空格)skip_header
:跳过开头几行usecols
:选择读取哪些列dtype
:指定数据类型
二进制文件
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
# 保存单个数组(.npy 格式)
np.save('array.npy', a)
# 读取
loaded = np.load('array.npy')
print(loaded)
# 保存多个数组(.npz 格式,无压缩)
b = np.array([7, 8, 9])
np.savez('arrays.npz', array1=a, array2=b)
# 读取
data = np.load('arrays.npz')
print(data['array1']) # [[1 2 3] [4 5 6]]
print(data['array2']) # [7 8 9]
print(data.files) # ['array1', 'array2']
# 保存多个数组(压缩格式)
np.savez_compressed('arrays_compressed.npz', array1=a, array2=b)
# 比较文件大小
import os
print(f"无压缩: {os.path.getsize('arrays.npz')} bytes")
print(f"压缩: {os.path.getsize('arrays_compressed.npz')} bytes")
tip
文件格式选择:
-
文本文件 (.txt, .csv):
- 优点:可读、可用其他工具打开
- 缺点:文件大、读写慢
- 适用:小数据、需要可读性
-
二进制文件 (.npy, .npz):
- 优点:文件小、读写快、保留精度
- 缺点:需要NumPy才能读取
- 适用:大数据、Python内部使用
# 大小对比
import numpy as np
a = np.arange(10000.)
np.savetxt('a.txt', a)
np.save('a.npy', a)
import os
print(f"文本文件: {os.path.getsize('a.txt')} bytes") # ~150KB
print(f"二进制文件: {os.path.getsize('a.npy')} bytes") # ~80KB