ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

数学建模入门:从NumPy基础到实战数据处理与性能优化

数学建模入门:从NumPy基础到实战数据处理与性能优化 1. 项目概述为什么数学建模要从NumPy开始如果你正准备用Python参加数学建模比赛或者刚刚开始接触这个领域可能会被各种算法、模型和论文搞得眼花缭乱。很多人一上来就想研究复杂的神经网络、时间序列预测结果在第一步数据处理上就卡住了——加载一个CSV文件都慢得不行做个简单的矩阵运算内存就爆了。我见过太多队伍把宝贵的三天时间花在了调试基础代码上而不是思考模型本身。这就像盖楼不打地基楼越高塌得越快。数学建模的核心无论是国赛、美赛还是亚太杯本质上都是“用数学工具解决实际问题”。这个过程离不开三样东西数据、计算和算法。而Python之所以成为建模的绝对主流正是因为它有强大的生态库来支撑这三个支柱。在所有这些库中NumPy不是“之一”而是“基石”。它提供了高效处理数组和矩阵的能力几乎所有后续的科学计算库如Pandas, SciPy, Scikit-learn都构建在NumPy之上。你的数据清洗、特征工程、模型计算底层流淌的都是NumPy的血液。所以这个“Week1”的安排非常务实。它不是教你花哨的算法而是让你掌握建模的“内功”。学好NumPy意味着你能自如地操控数据将数学模型往往是一组方程或矩阵运算快速转化为可执行的代码。当别人还在为如何向量化一个循环而头疼时你已经能写出简洁高效的代码节省出大量时间用于模型优化和论文写作。接下来我们就抛开那些空洞的理论直接进入实战看看NumPy在数学建模中到底怎么用。2. 核心需求解析数学建模对NumPy的依赖点在深入代码之前我们必须搞清楚数学建模的哪些环节非用NumPy不可。理解了“为什么”后面的“怎么做”才会更有方向。2.1 效率需求告别缓慢的Python原生循环Python的for循环在处理大规模数值计算时性能是硬伤。数学建模的数据动辄成千上万行一个简单的遍历求和都可能成为瓶颈。NumPy的底层是C语言实现的并且使用了向量化操作。所谓向量化就是一次对整个数组进行操作而不是逐个元素处理。举个例子计算两个向量的点积。用纯Python循环你需要遍历索引逐个相乘再累加。用NumPy就是一句np.dot(a, b)。后者不仅代码简洁速度可能快上几十甚至上百倍。在建模竞赛争分夺秒的环境下这种效率提升是决定性的。2.2 数据结构需求矩阵与高维数组的自然表达很多数学模型天生就是矩阵形式。比如线性规划中的约束系数矩阵、图论中的邻接矩阵、主成分分析中的协方差矩阵。用Python原生的列表嵌套列表来表示矩阵非常笨拙且容易出错比如确保每行长度一致。NumPy的ndarrayN-dimensional array专门为此设计它保证了数组中所有元素类型相同在内存中连续存储并且提供了一整套直观的矩阵操作语法如转置.T、求逆np.linalg.inv、矩阵乘法操作符。2.3 功能需求内置的数学与统计函数库数学建模涉及大量基础运算求解线性方程组、计算特征值、进行傅里叶变换、生成随机数用于模拟。如果自己实现这些功能不仅容易出错而且极其耗时。NumPy的numpy.linalg线性代数、numpy.random随机数、numpy.fft傅里叶变换等子模块提供了经过高度优化的可靠实现。你只需要调用一个函数就能获得工业级的计算结果。2.4 生态兼容需求数据流通的“标准货币”在Python的数据科学生态中NumPy数组是事实上的标准数据格式。你用Pandas读取的DataFrame其底层是NumPy数组用Matplotlib绘图传入的数据也通常是NumPy数组Scikit-learn的模型接收和返回的同样是NumPy数组。掌握了NumPy你就掌握了与这些强大库无缝对接的钥匙数据可以在不同工具间流畅转换不会卡在格式转换上。注意很多新手会忽视这个兼容性问题在Pandas和纯列表之间来回转换导致代码冗杂且效率低下。最佳实践是尽早将数据转换为NumPy数组进行核心计算仅在需要标签索引或数据框操作时才使用Pandas。3. 环境搭建与NumPy快速上手工欲善其事必先利其器。一个稳定、隔离的Python环境是高效学习和竞赛的保障。我强烈建议你放弃系统自带的Python使用conda或venv创建独立的虚拟环境。3.1 创建并激活虚拟环境使用conda如果你安装了Anaconda或Miniconda是更简单的方式因为它能很好地处理科学计算包的依赖。# 创建一个名为math_modelingPython版本为3.9的环境 conda create -n math_modeling python3.9 # 激活环境 conda activate math_modeling如果你使用纯Python可以使用venvpython -m venv math_modeling_env # 在Windows上激活 math_modeling_env\Scripts\activate # 在macOS/Linux上激活 source math_modeling_env/bin/activate3.2 安装NumPy及相关库环境激活后使用pip安装。对于数学建模我建议一次性安装好这个基础套装避免后续来回折腾。pip install numpy pandas matplotlib scipy scikit-learn jupyter安装完成后可以在Python中验证import numpy as np print(np.__version__) # 查看NumPy版本建议使用1.20以上版本 print(np.show_config()) # 查看NumPy的编译配置确认是否使用了优化如MKL、OpenBLAS3.3 理解NumPy的核心对象ndarrayNumPy的一切都围绕着ndarrayN维数组展开。它与Python列表有本质区别同质性数组中的所有元素必须是相同的数据类型如float64,int32。预定义大小创建数组时其大小就已固定改变大小会创建新数组。向量化操作运算会应用到整个数组而不是通过循环。创建数组最常用的几种方式import numpy as np # 从列表创建 arr1 np.array([1, 2, 3, 4]) # 一维数组 arr2 np.array([[1, 2, 3], [4, 5, 6]]) # 二维数组矩阵 # 使用内置函数快速创建 zeros_arr np.zeros((3, 4)) # 3行4列的全0矩阵 ones_arr np.ones((2, 2, 2)) # 2x2x2的全1三维数组 range_arr np.arange(0, 10, 2) # 类似range生成[0, 2, 4, 6, 8] linspace_arr np.linspace(0, 1, 5) # 在0到1之间生成5个等间距点输出[0., 0.25, 0.5, 0.75, 1.] # 生成随机数组建模中极其常用 random_arr np.random.rand(3, 3) # 生成3x3的[0,1)均匀分布随机数 normal_arr np.random.randn(100) # 生成100个标准正态分布随机数实操心得在建模中np.random模块的种子设置非常重要。为了结果可复现在代码开头使用np.random.seed(42)固定随机种子。这样每次运行生成的“随机”数据都是一样的便于调试和验证模型。4. 数学建模核心操作一数组索引、切片与变形数据处理的第一步往往是提取和重组数据。NumPy的索引功能强大且灵活但用法需要精确掌握。4.1 基础索引与切片语法与列表类似但对于多维数组可以用逗号分隔不同维度的索引。arr np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) # 取单个元素第2行第3列注意索引从0开始 elem arr[1, 2] # 值为7 # 切片取前两行的第2到第4列不含第4列 sub_arr arr[:2, 1:3] # 输出[[2, 3], [6, 7]] # 取整行第1行 row arr[0, :] # 等价于 arr[0]输出[1, 2, 3, 4] # 取整列第3列 col arr[:, 2] # 输出[3, 7, 11]4.2 布尔索引与花式索引这是建模中筛选数据的利器。# 布尔索引筛选出大于5的元素 mask arr 5 filtered arr[mask] # 输出一维数组[6, 7, 8, 9, 10, 11, 12] # 更复杂的条件组合筛选出大于5且是偶数的元素 mask_complex (arr 5) (arr % 2 0) filtered_complex arr[mask_complex] # 输出[6, 8, 10, 12] # 花式索引用整数数组索引选取指定的行或列 rows_to_pick [0, 2] cols_to_pick [1, 3] picked arr[rows_to_pick][:, cols_to_pick] # 先选行再选列。输出[[2, 4], [10, 12]] # 更简洁的写法arr[np.ix_(rows_to_pick, cols_to_pick)]4.3 数组变形与拼接模型常常要求输入特定形状的数据。# 改变形状元素总数不变 arr np.arange(12) reshaped arr.reshape(3, 4) # 变成3行4列 # 注意reshape返回新视图如果内存连续而非复制数据。使用arr.reshape(-1, 4)可以让NumPy自动计算行数。 # 展平数组 flattened reshaped.flatten() # 返回一份拷贝一维数组 raveled reshaped.ravel() # 返回一个视图如果可能修改会影响原数组 # 拼接数组 a np.array([[1, 2], [3, 4]]) b np.array([[5, 6], [7, 8]]) # 垂直拼接增加行 v_stack np.vstack((a, b)) # 或 np.concatenate((a, b), axis0) # 水平拼接增加列 h_stack np.hstack((a, b)) # 或 np.concatenate((a, b), axis1)注意事项reshape操作要求新形状的元素总数与原数组相同。resize方法则不同如果新形状更大会填充0更小则会截断数据。在建模中明确你的意图谨慎选择。5. 数学建模核心操作二向量化计算与广播机制这是NumPy性能与优雅的源泉也是新手和老手的关键分水岭。5.1 向量化计算用数组运算代替循环假设你有一个模型需要计算一组数据的平方和误差。纯Python写法data [1.2, 2.5, 3.1, 4.8] prediction 2.0 squared_errors [] for x in data: squared_errors.append((x - prediction) ** 2) mse sum(squared_errors) / len(data)NumPy向量化写法data np.array([1.2, 2.5, 3.1, 4.8]) prediction 2.0 squared_errors (data - prediction) ** 2 # 一次性对整个数组进行减法和平方运算 mse squared_errors.mean() # 调用数组方法求均值向量化版本不仅代码简洁而且由于在C层进行循环速度极快。在建模中应时刻思考如何将循环操作转化为对整个数组的运算。5.2 广播机制不同形状数组间的运算规则广播是NumPy中一个非常强大的概念它允许不同形状的数组进行算术运算。规则可以简化为两条从尾部维度开始逐一比较两个数组的维度大小。维度大小相等或其中一个为1或其中一个数组在该维度上不存在则广播兼容。看几个建模中的典型例子# 例1数组与标量运算最常见的广播 arr np.array([[1, 2, 3], [4, 5, 6]]) result arr 10 # 标量10被广播到与arr相同的形状 # 例2行向量与列向量相加 row np.array([1, 2, 3]) # 形状(3,) col np.array([[1], [2], [3]]) # 形状(3,1) # row被广播为(3,3)[[1,2,3], [1,2,3], [1,2,3]] # col被广播为(3,3)[[1,1,1], [2,2,2], [3,3,3]] result row col # 输出3x3矩阵 # 例3在数据标准化中的应用 (X - mean) / std data np.random.randn(100, 5) # 100个样本5个特征 mean data.mean(axis0) # 沿样本轴第0轴求均值得到形状(5,)的向量代表每个特征的均值 std data.std(axis0) # 得到形状(5,)的向量代表每个特征的标准差 normalized_data (data - mean) / std # data形状(100,5)mean/std形状(5,)触发广播理解广播能让你写出极其简洁的代码来处理数据标准化、矩阵与向量运算等常见任务。6. 数学建模核心操作三线性代数与随机数生成这部分是数学模型实现的直接工具。6.1 线性代数运算 (numpy.linalg)求解线性方程组是建模中的家常便饭。import numpy.linalg as LA # 假设有方程组 1*x 2*y 5 # 3*x 4*y 11 # 系数矩阵 A [[1, 2], [3, 4]] # 常数向量 b [5, 11] A np.array([[1., 2.], [3., 4.]]) b np.array([5., 11.]) # 方法1直接求逆计算量大数值稳定性差不推荐用于大矩阵 x LA.inv(A).dot(b) # 方法2使用solve函数推荐 x LA.solve(A, b) # 输出[1., 2.]即x1, y2 print(f解为{x}) # 其他常用操作 # 计算行列式 det_A LA.det(A) # 计算特征值和特征向量用于PCA等降维算法 eigenvalues, eigenvectors LA.eig(A) # 计算矩阵的范数 norm_A LA.norm(A, ordfro) # Frobenius范数6.2 随机数生成 (numpy.random)蒙特卡洛模拟、随机抽样、初始化模型参数都离不开它。# 设置随机种子确保可复现性 np.random.seed(2023) # 均匀分布 uniform_samples np.random.rand(1000) # [0,1)均匀分布 uniform_range np.random.uniform(low-5, high5, size100) # 指定范围 # 正态高斯分布 normal_samples np.random.randn(1000) # 标准正态分布 N(0,1) normal_custom np.random.normal(loc10, scale2, size100) # 均值10标准差2 # 整数随机数 integers np.random.randint(low0, high100, size50) # [0,100)的整数 # 随机抽样 data np.arange(100) sampled np.random.choice(data, size10, replaceFalse) # 无放回抽取10个样本实操心得在建模论文中如果使用了随机过程务必在论文或代码注释中写明使用的随机种子。这是科学可复现性的基本要求。评委或读者需要能重现你的结果。7. 实战案例一个完整的数学建模数据预处理流程让我们通过一个模拟的数学建模场景串联起上述知识点。假设我们拿到了一份某城市共享单车站点的数据需要为后续的供需预测模型做准备。7.1 模拟数据生成与加载import numpy as np import pandas as pd # 这里用Pandas模拟数据加载实际建模中数据常来自CSV # 设置随机种子 np.random.seed(42) # 模拟生成数据假设有50个站点记录了一周7天每天24小时的初始自行车数量需求模拟 n_stations 50 n_days 7 n_hours 24 # 生成一个三维数组站点 x 天数 x 小时 # 假设每个站点基础车辆数在20-50之间并加上随时间小时的波动 base_bikes np.random.randint(20, 51, sizen_stations) # 创建一个小时波动模式例如早晚高峰需求高 hourly_pattern np.sin(np.linspace(0, 2*np.pi, n_hours)) * 10 30 # 生成一个正弦波形状的基础需求 # 使用广播生成三维数据 # 外积将站点基础向量 (50,) 与小时模式向量 (24,) 结合得到 (50, 24) 的矩阵 # 然后增加一个天数维度并添加一些随机噪声 bike_data np.outer(base_bikes, hourly_pattern).reshape(n_stations, 1, n_hours) bike_data np.repeat(bike_data, n_days, axis1) # 将一天的模式重复7天 # 添加一些随机噪声和周末效应 noise np.random.randn(n_stations, n_days, n_hours) * 5 # 标准差为5的噪声 weekend_boost np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.5, 1.8]) # 周末需求增加 weekend_factor weekend_boost.reshape(1, n_days, 1) # 重塑为可广播的形状(1,7,1) bike_data bike_data * weekend_factor noise bike_data np.maximum(bike_data, 0).astype(np.int32) # 确保非负并转为整数 print(f数据形状{bike_data.shape}) # 应输出 (50, 7, 24) print(f数据预览第一个站点第一天\n{bike_data[0, 0, :10]}) # 查看前10小时7.2 数据清洗与异常值处理现实数据总有瑕疵。# 1. 处理缺失值假设我们随机插入一些NaN mask_nan np.random.rand(*bike_data.shape) 0.01 # 随机选择1%的数据点为缺失值 bike_data_with_nan bike_data.astype(np.float64) # 转为浮点以容纳NaN bike_data_with_nan[mask_nan] np.nan # 方法A用该站点该小时在所有天的中位数填充对时间序列常用 # 为了演示我们计算每个站点、每个小时跨7天的中位数 # 忽略NaN计算中位数 from numpy import nanmedian # 一种实现方式重塑数据以便计算 filled_data bike_data_with_nan.copy() for i in range(n_stations): for h in range(n_hours): hour_slice bike_data_with_nan[i, :, h] if np.isnan(hour_slice).any(): median_val np.nanmedian(hour_slice) filled_data[i, :, h] np.where(np.isnan(hour_slice), median_val, hour_slice) # 方法B简单情况用全局均值或固定值填充 # filled_data[np.isnan(filled_data)] np.nanmean(filled_data) # 2. 处理异常值假设车辆数超过100为异常 # 使用布尔索引找出异常值位置 outlier_mask filled_data 100 print(f发现 {outlier_mask.sum()} 个异常高值) # 策略用该站点该小时的历史分位数如95%分位数替换这里简化为用100截断 filled_data[outlier_mask] 1007.3 特征工程构造模型输入特征原始数据需要转化为模型友好的特征。# 将三维数据展平为二维样本 x 特征这是大多数机器学习模型要求的格式 # 每个样本是一个“站点-天”特征是该站24小时的数据 samples filled_data.reshape(n_stations * n_days, n_hours) print(f特征矩阵形状{samples.shape}) # (350, 24) # 构造衍生特征这能极大提升模型效果 # 例如早高峰7-9点平均需求、晚高峰17-19点平均需求、全天均值、标准差、最小值、最大值等 morning_hours list(range(7, 10)) evening_hours list(range(17, 20)) morning_mean samples[:, morning_hours].mean(axis1, keepdimsTrue) evening_mean samples[:, evening_hours].mean(axis1, keepdimsTrue) daily_mean samples.mean(axis1, keepdimsTrue) daily_std samples.std(axis1, keepdimsTrue) daily_max samples.max(axis1, keepdimsTrue) daily_min samples.min(axis1, keepdimsTrue) # 将所有特征水平拼接 engineered_features np.hstack([ samples, # 原始24小时特征 morning_mean, evening_mean, daily_mean, daily_std, daily_max, daily_min ]) print(f工程化特征矩阵形状{engineered_features.shape}) # (350, 24630)7.4 数据标准化与数据集划分# 标准化使每个特征均值为0标准差为1有助于许多模型如SVM、神经网络的收敛 from sklearn.preprocessing import StandardScaler # 这里用scikit-learn底层是NumPy scaler StandardScaler() features_scaled scaler.fit_transform(engineered_features) # 手动实现标准化理解原理 # mean_vec engineered_features.mean(axis0) # std_vec engineered_features.std(axis0) # features_scaled_manual (engineered_features - mean_vec) / std_vec # np.allclose(features_scaled, features_scaled_manual) # 应返回True # 划分训练集和测试集例如用前6天训练最后1天测试 n_train_days 6 train_indices np.where(np.arange(n_days).reshape(1, -1) n_train_days)[1] test_indices np.where(np.arange(n_days).reshape(1, -1) n_train_days)[1] # 利用花式索引选取数据 train_data features_scaled[np.isin(np.arange(samples.shape[0]) // n_stations, train_indices)] test_data features_scaled[np.isin(np.arange(samples.shape[0]) // n_stations, test_indices)] print(f训练集大小{train_data.shape} 测试集大小{test_data.shape})通过这个完整的流程你将原始的三维时序数据清洗、转换、标准化成了可供机器学习模型直接使用的二维特征矩阵。这个过程几乎涵盖了数学建模前期80%的数据处理工作而NumPy是完成这一切的核心工具。8. 性能优化与内存管理技巧当处理真正的大规模建模数据如数GB的遥感图像、社交网络关系矩阵时性能与内存成为瓶颈。以下是一些实战技巧。8.1 选择合适的数据类型NumPy数组默认是float64双精度浮点数但很多时候我们不需要这么高的精度。arr_default np.ones((1000, 1000)) # 默认float64占用内存 1000*1000*8 bytes ≈ 7.63 MB arr_float32 np.ones((1000, 1000), dtypenp.float32) # float32占用内存约 3.81 MB arr_int16 np.ones((1000, 1000), dtypenp.int16) # int16占用内存约 1.91 MB # 查看数据类型和内存占用 print(f默认类型{arr_default.dtype}, 内存{arr_default.nbytes / 1024**2:.2f} MB) print(ffloat32类型{arr_float32.dtype}, 内存{arr_float32.nbytes / 1024**2:.2f} MB) # 转换现有数组类型 arr_converted arr_default.astype(np.float32) # 注意这会创建新数组对于大部分机器学习任务float32精度已足够且能节省一半内存计算速度也更快。8.2 避免不必要的拷贝利用视图NumPy许多操作返回的是原数据的“视图”view而非“拷贝”copy。理解这点能避免内存爆炸。arr np.arange(10) # 切片操作返回视图 view_of_arr arr[3:7] # 这是一个视图与arr共享数据 view_of_arr[0] 999 print(arr[3]) # 输出 999原数组被修改了 # 显式拷贝 copy_of_arr arr[3:7].copy() copy_of_arr[0] 0 print(arr[3]) # 仍然是 999原数组未受影响 # reshape通常返回视图如果内存连续 original np.arange(12).reshape(3,4) reshaped original.reshape(4,3) reshaped[0,0] 99 print(original[0,0]) # 输出 99数据被修改8.3 使用向量化函数与np.einsum对于复杂的多维数组运算np.einsum爱因斯坦求和约定是一个神器它能以极其简洁的符号表达复杂的线性代数操作且底层优化极好。# 假设我们有三个矩阵 A, B, C想计算 sum_ij A_ij * B_jk * C_kl A np.random.randn(100, 200) B np.random.randn(200, 300) C np.random.randn(300, 50) # 传统方法多次矩阵乘法 result_traditional A.dot(B).dot(C) # 使用einsum result_einsum np.einsum(ij,jk,kl-il, A, B, C) np.allclose(result_traditional, result_einsum) # 应返回Trueeinsum的表达式ij,jk,kl-il直接指明了输入数组的维度下标和输出下标不仅写法简洁而且NumPy能据此优化计算路径通常比连续dot更快尤其是在涉及多个矩阵时。8.4 利用out参数进行原地操作许多NumPy函数如np.add,np.multiply,np.dot支持out参数可以将结果直接写入一个已分配的数组避免创建临时数组。# 不推荐产生多个临时数组 result A B result result * C # 推荐预分配输出数组使用out参数 result np.empty_like(A) # 预分配与A形状相同的空数组 np.add(A, B, outresult) # 将AB的结果直接存入result np.multiply(result, C, outresult) # 再将result与C相乘结果仍存回result在处理超大数组的迭代计算中这种技巧能显著减少内存分配开销。9. 常见问题与排查技巧实录即使掌握了基本操作在实际编码中你仍会遇到各种报错和意外情况。下面是我在带队和教学中总结的一些高频问题。9.1 维度不匹配与广播错误问题ValueError: operands could not be broadcast together with shapes...场景尝试将形状为(3,4)的数组与形状为(3,)的数组相加。原因根据广播规则(3,)可以广播为(1,3)但无法与(3,4)的第二个维度4兼容。解决a np.ones((3,4)) b np.array([1,2,3]) # 形状(3,) # 错误c a b # 正确方法1将b变为列向量(3,1)这样就能广播到(3,4) b_col b.reshape(-1, 1) # 或 b[:, np.newaxis] c a b_col # 正确方法2如果本意是每行加相同的标量则b应为(4,)的行向量 b_row np.array([1,2,3,4]) c a b_row排查技巧遇到广播错误立刻打印出所有操作数的.shape属性然后手动套用广播规则检查。9.2 索引越界与切片困惑问题IndexError: index X is out of bounds for axis Y with size Z场景数组只有3行却尝试访问arr[3]。解决记住Python是0索引最大有效索引是size-1。使用arr.shape查看各维度大小。另一个常见困惑切片是“左闭右开”区间。arr np.arange(10) # [0,1,2,...,9] print(arr[2:5]) # 输出 [2,3,4]包含索引2不包含索引5 print(arr[:5]) # 输出 [0,1,2,3,4] print(arr[5:]) # 输出 [5,6,7,8,9] print(arr[-3:]) # 输出最后三个元素 [7,8,9]9.3 数据类型导致的意外结果问题整数除法结果错误。arr_int np.array([1, 2, 3, 4]) result arr_int / 2 print(result) # 输出 [0.5, 1., 1.5, 2.]自动转为浮点了不在Python3和NumPy中除法默认产生浮点。 # 但如果想要整数除法向下取整需要使用 // result_floor arr_int // 2 # 输出 [0, 1, 1, 2]问题布尔数组与整数数组的混淆。arr np.array([1, 2, 3]) bool_idx np.array([True, False, True]) # 正确布尔索引 print(arr[bool_idx]) # 输出 [1, 3] # 错误但可能不报错整数索引 int_idx np.array([0, 2]) print(arr[int_idx]) # 输出 [1, 3]这里int_idx被解释为位置索引而非布尔值。关键明确你的索引数组是布尔类型还是整数类型它们的行为完全不同。9.4 函数或属性不存在错误问题AttributeError: module numpy has no attribute xxx场景如网络热词中提到的module numpy has no attribute trapz或product。原因函数位于子模块中或函数名拼写错误或NumPy版本差异。解决np.trapz存在用于梯形法数值积分。确认拼写。np.product不存在应为np.prod。常用函数归属线性代数np.linalg.inv,np.linalg.norm随机数np.random.randn,np.random.randint数学函数np.sin,np.exp,np.log统计np.mean,np.std,np.median使用dir(np)或help(np)查看模块内容或在官方文档中搜索。9.5 内存不足与性能瓶颈问题处理大数组时程序变慢或崩溃。排查与解决监控内存使用arr.nbytes查看数组内存占用。对于超大数组考虑使用dtype降级如float64-float32。使用内存映射文件对于远超内存的数据使用np.memmap。# 创建一个内存映射文件它不会一次性加载到内存 mmap_arr np.memmap(large_array.dat, dtypefloat32, modew, shape(10000, 10000)) # 可以像普通数组一样操作部分数据 mmap_arr[:1000, :1000] np.random.randn(1000, 1000).astype(np.float32)识别瓶颈使用%timeit魔术命令在Jupyter中或time模块对代码段进行计时。通常瓶颈在于未向量化的Python循环。利用np.einsum和np.dot对于矩阵运算尽量使用这些高度优化的函数避免自己写循环。考虑使用稀疏矩阵如果数据中大部分是0例如图邻接矩阵使用scipy.sparse可以节省大量内存和计算时间。掌握NumPy是一个从“会用”到“精通”的渐进过程。在数学建模的紧张赛程中扎实的NumPy功底能让你把更多精力投入在模型构建和论文写作上而不是与基础语法和性能问题作斗争。最好的学习方法就是动手实践找一个往年的赛题数据集用NumPy从头到尾处理一遍你遇到的每一个错误和解决的每一个问题都会成为你宝贵的经验。
返回列表