
👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕NumPy这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!
文章目录
- Python NumPy – 统计函数 计算数组的最大值与最小值 📊
-
- 引言
- NumPy 简介
- 基础概念:最大值与最小值
-
- 最大值 (Maximum)
- 最小值 (Minimum)
- NumPy 中的基本统计函数
-
- np.max() 和 np.min() 函数
- 多维数组中的最大值与最小值
- np.argmax() 和 np.argmin() 函数
- 高级统计函数
-
- np.ptp() 函数 (Peak to Peak)
- 处理特殊值
- 实际应用场景
-
- 股票价格分析
- 温度数据分析
- 学生成绩分析
- 性能比较与优化
- 错误处理与最佳实践
- 高级应用技巧
-
- 条件筛选下的极值计算
- 移动窗口极值计算
- 与其他库的集成
-
- 与 Pandas 结合
- 与 Matplotlib 结合进行可视化
- 实用工具函数封装
- 性能优化建议
-
- 1. 合理选择数据类型
- 2. 利用并行计算
- 常见陷阱与解决方案
-
- 1. 空数组处理
- 2. NaN 值处理
- 实际项目案例
- 总结与展望
-
- 关键要点回顾:
- 最佳实践建议:
Python NumPy – 统计函数 计算数组的最大值与最小值 📊
引言
在数据分析和科学计算的世界中,寻找数据集中的最大值和最小值是最基础也是最重要的统计操作之一。无论是分析股票价格的波动范围、测量温度变化的极值,还是评估学生考试成绩的分布情况,我们都需要能够快速准确地找到这些关键的统计指标。
Python 的 NumPy 库作为科学计算的核心工具,提供了强大而高效的函数来处理这类统计问题。今天,我们将深入探讨如何使用 NumPy 来计算数组的最大值与最小值,以及相关的统计函数应用。🚀
NumPy 简介
NumPy(Numerical Python)是 Python 中用于科学计算的基础库,它提供了高性能的多维数组对象和用于操作这些数组的工具。NumPy 是许多其他科学计算库的基础,如 Pandas、SciPy 和 scikit-learn。
NumPy 的核心优势在于:
- 高效性:底层用 C 语言实现,运算速度快
- 内存效率:连续的内存存储,减少内存开销
- 向量化操作:支持数组级别的数学运算
- 丰富的函数库:包含大量数学、统计和逻辑函数
基础概念:最大值与最小值
在统计学中,最大值和最小值被称为极值(extreme values),它们代表了数据集中数值的边界。这些值对于理解数据的范围、分布特征以及识别异常值都非常重要。
最大值 (Maximum)
最大值是数据集中最大的数值,它帮助我们了解数据的上限。
最小值 (Minimum)
最小值是数据集中最小的数值,它帮助我们了解数据的下限。
NumPy 中的基本统计函数
让我们从最基础的函数开始,逐步深入了解 NumPy 提供的各种统计功能。
np.max() 和 np.min() 函数
这是最直接的方法来获取数组的最大值和最小值:
import numpy as np
# 创建一个简单的数组
arr = np.array([1, 5, 3, 9, 2, 7, 4])
print("原始数组:", arr)
# 计算最大值
max_value = np.max(arr)
print(f"最大值: {max_value} 🔼")
# 计算最小值
min_value = np.min(arr)
print(f"最小值: {min_value} 🔽")
# 使用 Python 内置函数对比
print(f"内置 max(): {max(arr)}")
print(f"内置 min(): {min(arr)}")
输出结果:
原始数组: [1 5 3 9 2 7 4]
最大值: 9 🔼
最小值: 1 🔽
内置 max(): 9
内置 min(): 1
多维数组中的最大值与最小值
当处理多维数组时,NumPy 提供了更灵活的方式来计算极值:
# 创建二维数组
arr_2d = np.array([[1, 5, 3],
[9, 2, 7],
[4, 8, 6]])
print("二维数组:")
print(arr_2d)
# 整个数组的最大值和最小值
print(f"整个数组最大值: {np.max(arr_2d)}")
print(f"整个数组最小值: {np.min(arr_2d)}")
# 沿着不同轴计算
print(f"每行的最大值: {np.max(arr_2d, axis=1)}")
print(f"每列的最大值: {np.max(arr_2d, axis=0)}")
print(f"每行的最小值: {np.min(arr_2d, axis=1)}")
print(f"每列的最小值: {np.min(arr_2d, axis=0)}")
输出结果:
二维数组:
[[1 5 3]
[9 2 7]
[4 8 6]]
整个数组最大值: 9
整个数组最小值: 1
每行的最大值: [5 9 8]
每列的最大值: [9 8 7]
每行的最小值: [1 2 4]
每列的最小值: [1 2 3]
让我们用 Mermaid 图表来可视化这个过程:
#mermaid-svg-n9FkV1tt5ZsTBdea{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-n9FkV1tt5ZsTBdea .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-n9FkV1tt5ZsTBdea .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-n9FkV1tt5ZsTBdea .error-icon{fill:#552222;}#mermaid-svg-n9FkV1tt5ZsTBdea .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-n9FkV1tt5ZsTBdea .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-n9FkV1tt5ZsTBdea .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-n9FkV1tt5ZsTBdea .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-n9FkV1tt5ZsTBdea .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-n9FkV1tt5ZsTBdea .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-n9FkV1tt5ZsTBdea .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-n9FkV1tt5ZsTBdea .marker{fill:#333333;stroke:#333333;}#mermaid-svg-n9FkV1tt5ZsTBdea .marker.cross{stroke:#333333;}#mermaid-svg-n9FkV1tt5ZsTBdea svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-n9FkV1tt5ZsTBdea p{margin:0;}#mermaid-svg-n9FkV1tt5ZsTBdea .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-n9FkV1tt5ZsTBdea .cluster-label text{fill:#333;}#mermaid-svg-n9FkV1tt5ZsTBdea .cluster-label span{color:#333;}#mermaid-svg-n9FkV1tt5ZsTBdea .cluster-label span p{background-color:transparent;}#mermaid-svg-n9FkV1tt5ZsTBdea .label text,#mermaid-svg-n9FkV1tt5ZsTBdea span{fill:#333;color:#333;}#mermaid-svg-n9FkV1tt5ZsTBdea .node rect,#mermaid-svg-n9FkV1tt5ZsTBdea .node circle,#mermaid-svg-n9FkV1tt5ZsTBdea .node ellipse,#mermaid-svg-n9FkV1tt5ZsTBdea .node polygon,#mermaid-svg-n9FkV1tt5ZsTBdea .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-n9FkV1tt5ZsTBdea .rough-node .label text,#mermaid-svg-n9FkV1tt5ZsTBdea .node .label text,#mermaid-svg-n9FkV1tt5ZsTBdea .image-shape .label,#mermaid-svg-n9FkV1tt5ZsTBdea .icon-shape .label{text-anchor:middle;}#mermaid-svg-n9FkV1tt5ZsTBdea .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-n9FkV1tt5ZsTBdea .rough-node .label,#mermaid-svg-n9FkV1tt5ZsTBdea .node .label,#mermaid-svg-n9FkV1tt5ZsTBdea .image-shape .label,#mermaid-svg-n9FkV1tt5ZsTBdea .icon-shape .label{text-align:center;}#mermaid-svg-n9FkV1tt5ZsTBdea .node.clickable{cursor:pointer;}#mermaid-svg-n9FkV1tt5ZsTBdea .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-n9FkV1tt5ZsTBdea .arrowheadPath{fill:#333333;}#mermaid-svg-n9FkV1tt5ZsTBdea .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-n9FkV1tt5ZsTBdea .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-n9FkV1tt5ZsTBdea .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-n9FkV1tt5ZsTBdea .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-n9FkV1tt5ZsTBdea .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-n9FkV1tt5ZsTBdea .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-n9FkV1tt5ZsTBdea .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-n9FkV1tt5ZsTBdea .cluster text{fill:#333;}#mermaid-svg-n9FkV1tt5ZsTBdea .cluster span{color:#333;}#mermaid-svg-n9FkV1tt5ZsTBdea div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-n9FkV1tt5ZsTBdea .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-n9FkV1tt5ZsTBdea rect.text{fill:none;stroke-width:0;}#mermaid-svg-n9FkV1tt5ZsTBdea .icon-shape,#mermaid-svg-n9FkV1tt5ZsTBdea .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-n9FkV1tt5ZsTBdea .icon-shape p,#mermaid-svg-n9FkV1tt5ZsTBdea .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-n9FkV1tt5ZsTBdea .icon-shape .label rect,#mermaid-svg-n9FkV1tt5ZsTBdea .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-n9FkV1tt5ZsTBdea .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-n9FkV1tt5ZsTBdea .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-n9FkV1tt5ZsTBdea :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
二维数组
计算方式
整体计算
按行计算
按列计算
max() = 9
min() = 1
max(axis=1) = [5,9,8]
min(axis=1) = [1,2,4]
max(axis=0) = [9,8,7]
min(axis=0) = [1,2,3]
np.argmax() 和 np.argmin() 函数
除了知道最大值和最小值本身,我们还经常需要知道它们的位置索引:
# 一维数组示例
arr = np.array([1, 5, 3, 9, 2, 7, 4])
# 获取最大值和最小值的索引
max_index = np.argmax(arr)
min_index = np.argmin(arr)
print(f"数组: {arr}")
print(f"最大值 {arr[max_index]} 在索引 {max_index} 处 📍")
print(f"最小值 {arr[min_index]} 在索引 {min_index} 处 📍")
# 二维数组示例
arr_2d = np.array([[1, 5, 3],
[9, 2, 7],
[4, 8, 6]])
print("\\n二维数组:")
print(arr_2d)
# 展平后的索引
flat_max_index = np.argmax(arr_2d)
flat_min_index = np.argmin(arr_2d)
print(f"展平后最大值索引: {flat_max_index}")
print(f"展平后最小值索引: {flat_min_index}")
# 按轴计算索引
row_max_indices = np.argmax(arr_2d, axis=1)
col_max_indices = np.argmax(arr_2d, axis=0)
print(f"每行最大值索引: {row_max_indices}")
print(f"每列最大值索引: {col_max_indices}")
输出结果:
数组: [1 5 3 9 2 7 4]
最大值 9 在索引 3 处 📍
最小值 1 在索引 0 处 📍
二维数组:
[[1 5 3]
[9 2 7]
[4 8 6]]
展平后最大值索引: 3
展平后最小值索引: 0
每行最大值索引: [1 0 1]
每列最大值索引: [1 2 1]
高级统计函数
NumPy 还提供了一些更高级的统计函数,可以帮助我们更好地理解和分析数据。
np.ptp() 函数 (Peak to Peak)
ptp 函数计算数组中最大值和最小值之间的差值,也就是峰峰值:
# 基本用法
arr = np.array([1, 5, 3, 9, 2, 7, 4])
peak_to_peak = np.ptp(arr)
print(f"数组: {arr}")
print(f"峰峰值 (最大值-最小值): {peak_to_peak} 📈")
# 多维数组示例
arr_2d = np.array([[1, 5, 3],
[9, 2, 7],
[4, 8, 6]])
print(f"\\n二维数组:")
print(arr_2d)
print(f"整体峰峰值: {np.ptp(arr_2d)}")
print(f"每行峰峰值: {np.ptp(arr_2d, axis=1)}")
print(f"每列峰峰值: {np.ptp(arr_2d, axis=0)}")
输出结果:
数组: [1 5 3 9 2 7 4]
峰峰值 (最大值-最小值): 8 📈
二维数组:
[[1 5 3]
[9 2 7]
[4 8 6]]
整体峰峰值: 8
每行峰峰值: [4 7 4]
每列峰峰值: [8 6 4]
处理特殊值
在实际数据分析中,我们经常会遇到包含 NaN(Not a Number)或无穷大的数组。NumPy 提供了相应的函数来处理这些特殊情况:
# 包含 NaN 的数组
arr_with_nan = np.array([1, 5, np.nan, 9, 2, 7, 4])
print(f"包含 NaN 的数组: {arr_with_nan}")
# 标准函数会返回 NaN
print(f"标准 max(): {np.max(arr_with_nan)}")
print(f"标准 min(): {np.min(arr_with_nan)}")
# 使用 nanmax 和 nanmin 忽略 NaN 值
print(f"忽略 NaN 的最大值: {np.nanmax(arr_with_nan)} ✅")
print(f"忽略 NaN 的最小值: {np.nanmin(arr_with_nan)} ✅")
# 包含无穷大的数组
arr_with_inf = np.array([1, 5, np.inf, 9, 2, –np.inf, 4])
print(f"\\n包含无穷大的数组: {arr_with_inf}")
print(f"包含 inf 的最大值: {np.max(arr_with_inf)}")
print(f"包含 -inf 的最小值: {np.min(arr_with_inf)}")
输出结果:
包含 NaN 的数组: [ 1. 5. nan 9. 2. 7. 4.]
标准 max(): nan
标准 min(): nan
忽略 NaN 的最大值: 9.0 ✅
忽略 NaN 的最小值: 1.0 ✅
包含无穷大的数组: [ 1. 5. inf 9. 2. -inf 4.]
包含 inf 的最大值: inf
包含 -inf 的最小值: -inf
实际应用场景
让我们通过一些实际的应用场景来展示这些函数的强大功能。
股票价格分析
假设我们要分析某只股票一周的价格变化:
# 模拟股票一周的收盘价
stock_prices = np.array([150.2, 152.8, 148.5, 155.3, 153.7, 151.9, 154.6])
days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
print("股票价格分析 📊")
print("=" * 30)
for day, price in zip(days, stock_prices):
print(f"{day}: ${price:.2f}")
print(f"\\n最高价格: ${np.max(stock_prices):.2f} ({days[np.argmax(stock_prices)]}) 📈")
print(f"最低价格: ${np.min(stock_prices):.2f} ({days[np.argmin(stock_prices)]}) 📉")
print(f"价格波动范围: ${np.ptp(stock_prices):.2f} 💰")
print(f"平均价格: ${np.mean(stock_prices):.2f} 📊")
输出结果:
股票价格分析 📊
==============================
周一: $150.20
周二: $152.80
周三: $148.50
周四: $155.30
周五: $153.70
周六: $151.90
周日: $154.60
最高价格: $155.30 (周四) 📈
最低价格: $148.50 (周三) 📉
价格波动范围: $6.80 💰
平均价格: $152.43 📊
温度数据分析
分析一个月内每天的最高温度:
# 模拟一个月的每日最高温度(摄氏度)
daily_temps = np.random.normal(25, 5, 30) # 平均25度,标准差5度
daily_temps = np.round(daily_temps, 1) # 四舍五入到一位小数
print("月度温度数据分析 ☀️")
print("=" * 40)
print(f"本月温度记录: {daily_temps}")
# 基本统计信息
max_temp = np.max(daily_temps)
min_temp = np.min(daily_temps)
avg_temp = np.mean(daily_temps)
temp_range = np.ptp(daily_temps)
print(f"\\n📊 统计结果:")
print(f"最高温度: {max_temp}°C (第{np.argmax(daily_temps)+1}天)")
print(f"最低温度: {min_temp}°C (第{np.argmin(daily_temps)+1}天)")
print(f"平均温度: {avg_temp:.1f}°C")
print(f"温度范围: {temp_range:.1f}°C")
# 分析温度分布
hot_days = np.sum(daily_temps > 30)
cold_days = np.sum(daily_temps < 20)
normal_days = len(daily_temps) – hot_days – cold_days
print(f"\\n🌡️ 温度分类:")
print(f"炎热天气 (>30°C): {hot_days} 天")
print(f"寒冷天气 (<20°C): {cold_days} 天")
print(f"温和天气 (20-30°C): {normal_days} 天")
学生成绩分析
分析班级学生的考试成绩:
# 模拟班级学生成绩
np.random.seed(42) # 设置随机种子以获得可重复的结果
student_scores = np.random.normal(75, 15, 45) # 平均分75,标准差15
student_scores = np.clip(student_scores, 0, 100) # 限制在0-100范围内
student_scores = np.round(student_scores, 0).astype(int) # 转换为整数
print("班级成绩分析 🎓")
print("=" * 30)
print(f"学生人数: {len(student_scores)}")
print(f"成绩列表: {student_scores}")
# 基本统计
highest_score = np.max(student_scores)
lowest_score = np.min(student_scores)
class_average = np.mean(student_scores)
score_range = np.ptp(student_scores)
print(f"\\n📈 成绩统计:")
print(f"最高分: {highest_score} 分")
print(f"最低分: {lowest_score} 分")
print(f"班级平均分: {class_average:.1f} 分")
print(f"分数跨度: {score_range} 分")
# 成绩等级分析
excellent = np.sum(student_scores >= 90) # 优秀 (90-100)
good = np.sum((student_scores >= 80) & (student_scores < 90)) # 良好 (80-89)
average_grade = np.sum((student_scores >= 70) & (student_scores < 80)) # 中等 (70-79)
passing = np.sum((student_scores >= 60) & (student_scores < 70)) # 及格 (60-69)
failing = np.sum(student_scores < 60) # 不及格 (<60)
print(f"\\n📊 成绩分布:")
print(f"优秀 (90-100): {excellent} 人 ({excellent/len(student_scores)*100:.1f}%)")
print(f"良好 (80-89): {good} 人 ({good/len(student_scores)*100:.1f}%)")
print(f"中等 (70-79): {average_grade} 人 ({average_grade/len(student_scores)*100:.1f}%)")
print(f"及格 (60-69): {passing} 人 ({passing/len(student_scores)*100:.1f}%)")
print(f"不及格 (<60): {failing} 人 ({failing/len(student_scores)*100:.1f}%)")
# 找出最高分和最低分的学生
top_student_index = np.argmax(student_scores)
worst_student_index = np.argmin(student_scores)
print(f"\\n🏆 特别表扬:")
print(f"最高分学生: 第{top_student_index+1}号同学 ({student_scores[top_student_index]}分)")
print(f"进步空间最大的学生: 第{worst_student_index+1}号同学 ({student_scores[worst_student_index]}分)")
性能比较与优化
让我们比较不同方法的性能,并探讨一些优化技巧:
import time
# 创建大型数组进行性能测试
large_array = np.random.rand(1000000)
# 测试不同的最大值计算方法
def test_performance():
methods = {
"np.max()": lambda x: np.max(x),
"built-in max()": lambda x: max(x.tolist()),
"manual loop": lambda x: manual_max(x)
}
results = {}
for name, method in methods.items():
start_time = time.time()
result = method(large_array)
end_time = time.time()
execution_time = end_time – start_time
results[name] = (result, execution_time)
print(f"{name}: {result:.6f} (耗时: {execution_time:.6f}秒) ⏱️")
return results
def manual_max(arr):
max_val = arr[0]
for val in arr[1:]:
if val > max_val:
max_val = val
return max_val
print("性能比较测试:")
print("=" * 40)
performance_results = test_performance()
# 分析结果
fastest_method = min(performance_results.keys(),
key=lambda x: performance_results[x][1])
print(f"\\n最快的方法: {fastest_method} 🏆")
错误处理与最佳实践
在实际使用中,我们需要考虑各种可能的错误情况:
def safe_extrema_analysis(arr):
"""
安全地分析数组的极值
"""
try:
# 检查数组是否为空
if arr.size == 0:
print("警告: 数组为空 ❌")
return None
# 检查是否包含非数值类型
if not np.issubdtype(arr.dtype, np.number):
print("警告: 数组包含非数值类型 ❌")
return None
# 计算基本统计信息
max_val = np.max(arr)
min_val = np.min(arr)
range_val = np.ptp(arr)
# 处理特殊值
if np.isnan(max_val) or np.isnan(min_val):
max_val = np.nanmax(arr)
min_val = np.nanmin(arr)
print("注意: 数组包含 NaN 值,已忽略处理 ⚠️")
result = {
'maximum': max_val,
'minimum': min_val,
'range': range_val,
'argmax': np.unravel_index(np.argmax(arr), arr.shape),
'argmin': np.unravel_index(np.argmin(arr), arr.shape)
}
return result
except Exception as e:
print(f"计算过程中发生错误: {e} ❌")
return None
# 测试安全函数
test_arrays = [
np.array([1, 2, 3, 4, 5]),
np.array([]),
np.array([1, 2, np.nan, 4, 5]),
np.array([[1, 2], [3, 4]])
]
for i, arr in enumerate(test_arrays):
print(f"\\n测试数组 {i+1}: {arr}")
result = safe_extrema_analysis(arr)
if result:
print(f"最大值: {result['maximum']}")
print(f"最小值: {result['minimum']}")
print(f"范围: {result['range']}")
print(f"最大值位置: {result['argmax']}")
print(f"最小值位置: {result['argmin']} ✅")
高级应用技巧
条件筛选下的极值计算
有时候我们只需要在满足特定条件的数据中找极值:
# 创建示例数据
data = np.random.randint(1, 101, 50) # 1-100的随机整数
print(f"原始数据: {data}")
# 找到大于50的所有数字中的最大值和最小值
filtered_data = data[data > 50]
if len(filtered_data) > 0:
filtered_max = np.max(filtered_data)
filtered_min = np.min(filtered_data)
print(f"大于50的数字: {filtered_data}")
print(f"其中最大值: {filtered_max} 🔼")
print(f"其中最小值: {filtered_min} 🔽")
else:
print("没有大于50的数字 ❌")
# 使用 np.where 进行条件筛选
condition = data > 50
where_result = np.where(condition, data, np.nan)
clean_where_result = where_result[~np.isnan(where_result)]
if len(clean_where_result) > 0:
print(f"使用 np.where 筛选结果的最大值: {np.nanmax(where_result)}")
print(f"使用 np.where 筛选结果的最小值: {np.nanmin(where_result)}")
移动窗口极值计算
在时间序列分析中,我们经常需要计算移动窗口内的极值:
def moving_extrema(data, window_size):
"""
计算移动窗口内的极值
"""
if len(data) < window_size:
return None
max_values = []
min_values = []
for i in range(len(data) – window_size + 1):
window = data[i:i+window_size]
max_values.append(np.max(window))
min_values.append(np.min(window))
return np.array(max_values), np.array(min_values)
# 示例:计算股价的5日移动极值
stock_prices = np.array([100, 102, 98, 105, 103, 107, 101, 109, 106, 104])
print(f"股价数据: {stock_prices}")
moving_max, moving_min = moving_extrema(stock_prices, 5)
print(f"5日移动最大值: {moving_max}")
print(f"5日移动最小值: {moving_min}")
# 可视化移动极值的概念
print("\\n移动窗口示例:")
for i in range(len(stock_prices) – 4):
window = stock_prices[i:i+5]
print(f"窗口{i+1}–{i+5}: {window} -> max={np.max(window)}, min={np.min(window)}")
与其他库的集成
NumPy 的统计函数可以很好地与其他数据科学库配合使用:
与 Pandas 结合
import pandas as pd
# 创建 DataFrame
df = pd.DataFrame({
'product_A': [100, 120, 95, 130, 110],
'product_B': [80, 85, 75, 90, 88],
'product_C': [150, 160, 145, 165, 155]
})
print("产品销售数据:")
print(df)
# 使用 NumPy 函数
print(f"\\n产品A的最大销量: {np.max(df['product_A'])}")
print(f"所有产品的最大销量: {np.max(df.values)}")
print(f"每种产品的最大销量: {np.max(df.values, axis=0)}")
print(f"每天的最大销量: {np.max(df.values, axis=1)}")
与 Matplotlib 结合进行可视化
虽然我们不显示图片,但可以展示如何准备数据用于可视化:
import matplotlib.pyplot as plt
# 生成示例数据
x = np.linspace(0, 10, 100)
y = np.sin(x) + np.random.normal(0, 0.1, 100)
# 计算极值用于标注
max_y_idx = np.argmax(y)
min_y_idx = np.argmin(y)
max_x = x[max_y_idx]
max_y = y[max_y_idx]
min_x = x[min_y_idx]
min_y = y[min_y_idx]
print("数据可视化准备:")
print(f"X轴范围: [{np.min(x):.2f}, {np.max(x):.2f}]")
print(f"Y轴范围: [{np.min(y):.2f}, {np.max(y):.2f}]")
print(f"最大值点: ({max_x:.2f}, {max_y:.2f})")
print(f"最小值点: ({min_x:.2f}, {min_y:.2f})")
# 准备标注文本
annotation_text = f"最大值: ({max_x:.2f}, {max_y:.2f})"
print(f"标注文本: {annotation_text}")
实用工具函数封装
让我们创建一些实用的工具函数来简化常见的极值计算任务:
class ExtremaAnalyzer:
"""
极值分析器类
"""
def __init__(self, data):
self.data = np.array(data)
self.results = {}
def analyze(self):
"""
全面分析数据的极值特征
"""
if self.data.size == 0:
return {"error": "Empty array"}
# 基本统计
self.results = {
'count': self.data.size,
'shape': self.data.shape,
'max_value': float(np.nanmax(self.data)),
'min_value': float(np.nanmin(self.data)),
'range': float(np.nanmax(self.data) – np.nanmin(self.data)),
'max_position': np.unravel_index(np.nanargmax(self.data), self.data.shape),
'min_position': np.unravel_index(np.nanargmin(self.data), self.data.shape)
}
# 百分位数
if not np.all(np.isnan(self.data)):
self.results['percentiles'] = {
'25%': float(np.nanpercentile(self.data, 25)),
'50%': float(np.nanpercentile(self.data, 50)),
'75%': float(np.nanpercentile(self.data, 75))
}
return self.results
def get_summary(self):
"""
获取简洁的摘要信息
"""
if not self.results:
self.analyze()
summary = f"""
📊 数据概览:
– 数据量: {self.results['count']}
– 形状: {self.results['shape']}
– 最大值: {self.results['max_value']:.2f}
– 最小值: {self.results['min_value']:.2f}
– 范围: {self.results['range']:.2f}
– 最大值位置: {self.results['max_position']}
– 最小值位置: {self.results['min_position']}
""".strip()
return summary
# 使用示例
sample_data = np.random.exponential(2, (3, 4)) * 10
analyzer = ExtremaAnalyzer(sample_data)
print("使用 ExtremaAnalyzer 类:")
print("=" * 40)
results = analyzer.analyze()
print(analyzer.get_summary())
# 显示详细结果
print(f"\\n详细分析结果:")
for key, value in results.items():
if key != 'percentiles':
print(f"{key}: {value}")
else:
print("百分位数:")
for p_key, p_value in value.items():
print(f" {p_key}: {p_value:.2f}")
性能优化建议
为了获得最佳性能,以下是一些建议:
1. 合理选择数据类型
# 比较不同数据类型的性能
int_array = np.random.randint(0, 1000, 1000000, dtype=np.int32)
float_array = np.random.rand(1000000).astype(np.float32)
double_array = np.random.rand(1000000).astype(np.float64)
def benchmark_dtype(arr, dtype_name):
import time
start = time.time()
result = np.max(arr)
end = time.time()
print(f"{dtype_name}: {result:.6f} (耗时: {(end–start)*1000:.3f}ms)")
print("数据类型性能比较:")
benchmark_dtype(int_array, "int32")
benchmark_dtype(float_array, "float32")
benchmark_dtype(double_array, "float64")
2. 利用并行计算
# 对于大型数组,NumPy 会自动利用多核处理器
large_array = np.random.rand(10000000)
# NumPy 的函数已经针对性能进行了优化
start_time = time.time()
max_val = np.max(large_array)
end_time = time.time()
print(f"大型数组最大值计算:")
print(f"数组大小: {large_array.size:,}")
print(f"最大值: {max_val:.6f}")
print(f"计算时间: {(end_time – start_time)*1000:.2f} ms ⚡")
常见陷阱与解决方案
1. 空数组处理
# 错误的做法
try:
empty_arr = np.array([])
max_val = np.max(empty_arr)
print(f"空数组最大值: {max_val}") # 这会产生 ValueError
except ValueError as e:
print(f"错误: {e} ❌")
# 正确的做法
def safe_max(arr):
if arr.size == 0:
return None
return np.max(arr)
empty_arr = np.array([])
result = safe_max(empty_arr)
print(f"安全的最大值计算: {result} ✅")
2. NaN 值处理
# 包含 NaN 的数组
nan_array = np.array([1, 2, np.nan, 4, 5])
# 错误的理解
wrong_max = np.max(nan_array)
print(f"包含 NaN 的最大值: {wrong_max} ❌") # 返回 NaN
# 正确的处理
correct_max = np.nanmax(nan_array)
correct_min = np.nanmin(nan_array)
print(f"忽略 NaN 的最大值: {correct_max} ✅")
print(f"忽略 NaN 的最小值: {correct_min} ✅")
实际项目案例
让我们看一个完整的实际项目案例:
class WeatherDataAnalyzer:
"""
天气数据分析器
"""
def __init__(self):
self.data = None
self.locations = []
def load_sample_data(self):
"""
加载示例天气数据
"""
# 模拟三个城市的温度数据
np.random.seed(123)
cities = ['北京', '上海', '广州']
days = 30
self.data = {}
for city in cities:
# 生成模拟温度数据
base_temp = {'北京': 5, '上海': 10, '广州': 20}[city]
temps = np.random.normal(base_temp, 8, days)
self.data[city] = np.clip(temps, –10, 40) # 限制合理范围
self.locations.append(city)
return self.data
def analyze_city_weather(self, city):
"""
分析单个城市天气
"""
if city not in self.data:
return None
temps = self.data[city]
analysis = {
'city': city,
'max_temp': float(np.max(temps)),
'min_temp': float(np.min(temps)),
'avg_temp': float(np.mean(temps)),
'temp_range': float(np.ptp(temps)),
'hottest_day': int(np.argmax(temps)) + 1,
'coldest_day': int(np.argmin(temps)) + 1,
'hot_days': int(np.sum(temps > 30)),
'cold_days': int(np.sum(temps < 0))
}
return analysis
def compare_cities(self):
"""
城市间天气对比
"""
all_analyses = []
for city in self.locations:
analysis = self.analyze_city_weather(city)
if analysis:
all_analyses.append(analysis)
# 找出极端城市
max_temps = [a['max_temp'] for a in all_analyses]
min_temps = [a['min_temp'] for a in all_analyses]
hottest_city_idx = np.argmax(max_temps)
coldest_city_idx = np.argmin(min_temps)
comparison = {
'analyses': all_analyses,
'hottest_city': all_analyses[hottest_city_idx],
'coldest_city': all_analyses[coldest_city_idx],
'temperature_range': float(np.ptp([a['max_temp'] for a in all_analyses]))
}
return comparison
def generate_report(self):
"""
生成完整报告
"""
if not self.data:
self.load_sample_data()
print("🌤️ 天气数据分析报告")
print("=" * 50)
# 单个城市分析
for city in self.locations:
analysis = self.analyze_city_weather(city)
print(f"\\n📍 {analysis['city']} 天气统计:")
print(f" 最高温度: {analysis['max_temp']:.1f}°C (第{analysis['hottest_day']}天)")
print(f" 最低温度: {analysis['min_temp']:.1f}°C (第{analysis['coldest_day']}天)")
print(f" 平均温度: {analysis['avg_temp']:.1f}°C")
print(f" 温度范围: {analysis['temp_range']:.1f}°C")
print(f" 高温天数: {analysis['hot_days']} 天 (>30°C)")
print(f" 寒冷天数: {analysis['cold_days']} 天 (<0°C)")
# 城市对比
comparison = self.compare_cities()
print(f"\\n🌍 城市对比:")
print(f" 最热城市: {comparison['hottest_city']['city']} "
f"({comparison['hottest_city']['max_temp']:.1f}°C)")
print(f" 最冷城市: {comparison['coldest_city']['city']} "
f"({comparison['coldest_city']['min_temp']:.1f}°C)")
print(f" 城市间温差: {comparison['temperature_range']:.1f}°C")
# 运行分析器
analyzer = WeatherDataAnalyzer()
analyzer.generate_report()
总结与展望
通过本文的详细介绍,我们可以看到 NumPy 提供的强大而灵活的统计函数来计算数组的最大值和最小值。这些函数不仅简单易用,而且经过高度优化,在处理大型数据集时表现出色。
关键要点回顾:
最佳实践建议:
NumPy 的统计函数是数据科学工作流程中不可或缺的工具。无论你是进行简单的数据分析还是复杂的科学计算,掌握这些函数都将大大提高你的工作效率。随着对这些函数的深入理解和熟练应用,你将能够在各种数据挑战面前游刃有余。🌟
在未来的学习中,建议继续探索 NumPy 的其他统计函数,如均值、方差、标准差等,以及更高级的数据分析技术。同时,也要关注相关库的发展,如 Pandas、SciPy 等,它们建立在 NumPy 之上,提供了更多专门化的数据分析功能。
记住,最好的学习方式是在实践中不断练习和应用这些知识。尝试将这些函数应用到你自己的项目中,你会发现它们的强大之处远远超出本文所介绍的内容。💪
想了解更多关于 NumPy 的信息,可以访问 NumPy 官方网站 获取最新的文档和教程。
对于更深入的数据分析需求,推荐学习 Pandas 文档,它是基于 NumPy 构建的强大数据分析库。
如果你对科学计算感兴趣,SciPy 文档 提供了更多高级数学和科学计算功能。
🙌 感谢你读到这里! 🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。 💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友! 💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿 🔔 关注我,不错过下一篇干货!我们下期再见!✨


