1. 引言
在 Python 数据分析生态中,agate是一个轻量级、不可变的数据分析库,专注于提供清晰、可读性强的 API。而agate-stats是 agate 的官方扩展包,为 agate 表格数据增加了丰富的统计计算能力。本文将详细阐述 agate-stats 包的功能、安装方法、核心语法与参数,并通过 8 个实际应用案例展示其用法,最后总结常见错误与使用注意事项。
2. agate-stats 包概述
2.1 什么是 agate-stats
agate-stats 是 agate 数据表格库的统计扩展模块。它提供了一系列统计方法,包括描述性统计、相关性分析、假设检验、回归分析等,让用户无需切换到 pandas 或 scipy 即可完成常见统计分析任务。
2.2 核心功能
- 描述性统计:均值、中位数、众数、方差、标准差、偏度、峰度等
- 相关性分析:Pearson 相关系数、Spearman 秩相关系数
- 假设检验:t 检验、卡方检验、ANOVA 等
- 回归分析:线性回归、多项式回归
- 分组统计:按分组计算各类统计量
- 滚动统计:移动平均、移动标准差等
3. 安装与配置
3.1 安装 agate-stats
agate-stats 可以通过 pip 直接安装:
pip install agate-stats安装完成后,agate-stats 会自动注册为 agate 的扩展,无需额外配置即可使用。
3.2 依赖关系
agate-stats 依赖以下核心库:
- agate(>=1.6.0):基础数据表格库
- numpy:数值计算支持
- scipy:统计函数支持
- six:Python 2/3 兼容支持
4. 核心语法与参数
4.1 基本数据准备
使用 agate-stats 前,需要先创建 agate 表格对象:
import agate import agatestats 注册统计扩展 agatestats.install() 创建示例数据 data = [ ('张三', 25, 85.5, 'A'), ('李四', 30, 92.0, 'B'), ('王五', 28, 78.5, 'A'), ('赵六', 35, 88.0, 'B'), ('孙七', 22, 95.5, 'A'), ] column_names = ['姓名', '年龄', '成绩', '班级'] column_types = [agate.Text(), agate.Number(), agate.Number(), agate.Text()] table = agate.Table(data, column_names, column_types)4.2 描述性统计方法
agate-stats 为表格的数值列提供了丰富的描述性统计方法:
# 均值 mean = table.columns['成绩'].mean() print(f"成绩均值: {mean}") 中位数 median = table.columns['成绩'].median() print(f"成绩中位数: {median}") 标准差 std = table.columns['成绩'].stdev() print(f"成绩标准差: {std}") 方差 variance = table.columns['成绩'].variance() print(f"成绩方差: {variance}") 偏度 skewness = table.columns['成绩'].skewness() print(f"成绩偏度: {skewness}") 峰度 kurtosis = table.columns['成绩'].kurtosis() print(f"成绩峰度: {kurtosis}")4.3 相关性分析
# Pearson 相关系数 pearson_r = table.columns['年龄'].pearson_correlation(table.columns['成绩']) print(f"年龄与成绩的 Pearson 相关系数: {pearson_r}") Spearman 秩相关系数 spearman_rho = table.columns['年龄'].spearman_correlation(table.columns['成绩']) print(f"年龄与成绩的 Spearman 相关系数: {spearman_rho}")4.4 假设检验
# 单样本 t 检验 t_stat, p_value = table.columns['成绩'].one_sample_t_test(80) print(f"t 统计量: {t_stat}, p 值: {p_value}") 独立样本 t 检验 group_a = table.where(lambda r: r['班级'] == 'A').columns['成绩'] group_b = table.where(lambda r: r['班级'] == 'B').columns['成绩'] t_stat, p_value = group_a.independent_t_test(group_b) print(f"独立样本 t 检验: t={t_stat}, p={p_value}")4.5 分组统计
# 按班级分组计算均值 grouped = table.group_by('班级') stats = grouped.aggregate([ ('成绩均值', agate.Mean('成绩')), ('成绩标准差', agate.Stdev('成绩')), ('人数', agate.Count()) ]) print(stats.print_table())5. 8 个实际应用案例
案例 1:销售数据描述性统计
分析某电商平台一周的日销售额数据:
import agate import agatestats agatestats.install() sales_data = [ ('周一', 12500), ('周二', 13800), ('周三', 11200), ('周四', 14600), ('周五', 16200), ('周六', 19800), ('周日', 17500), ] table = agate.Table(sales_data, ['日期', '销售额'], [agate.Text(), agate.Number()]) sales_col = table.columns['销售额'] print(f"日均销售额: {sales_col.mean():.2f}") print(f"销售额中位数: {sales_col.median():.2f}") print(f"销售额标准差: {sales_col.stdev():.2f}") print(f"销售额方差: {sales_col.variance():.2f}") print(f"销售额偏度: {sales_col.skewness():.3f}") print(f"销售额峰度: {sales_col.kurtosis():.3f}")案例 2:学生成绩相关性分析
分析学生数学成绩与物理成绩的相关性:
import agate import agatestats agatestats.install() student_data = [ ('学生A', 85, 78), ('学生B', 92, 88), ('学生C', 76, 72), ('学生D', 88, 85), ('学生E', 95, 91), ('学生F', 70, 65), ('学生G', 82, 80), ('学生H', 90, 87), ] table = agate.Table(student_data, ['姓名', '数学', '物理'], [agate.Text(), agate.Number(), agate.Number()]) math_col = table.columns['数学'] physics_col = table.columns['物理'] pearson_r = math_col.pearson_correlation(physics_col) spearman_rho = math_col.spearman_correlation(physics_col) print(f"数学与物理 Pearson 相关系数: {pearson_r:.4f}") print(f"数学与物理 Spearman 相关系数: {spearman_rho:.4f}") if abs(pearson_r) > 0.8: print("结论:数学与物理成绩呈强正相关") elif abs(pearson_r) > 0.5: print("结论:数学与物理成绩呈中等正相关") else: print("结论:数学与物理成绩相关性较弱")案例 3:A/B 测试结果分析
比较两种网页设计方案的转化率是否存在显著差异:
import agate import agatestats agatestats.install() ab_data = [ ('A方案', 120, 45), ('A方案', 135, 52), ('A方案', 110, 38), ('A方案', 128, 48), ('A方案', 142, 55), ('B方案', 115, 30), ('B方案', 130, 35), ('B方案', 108, 28), ('B方案', 122, 32), ('B方案', 140, 38), ] table = agate.Table(ab_data, ['方案', '访问量', '转化数'], [agate.Text(), agate.Number(), agate.Number()]) 计算转化率 table = table.compute([ ('转化率', agate.Formula(agate.Number(), lambda r: r['转化数'] / r['访问量'] * 100)) ]) group_a = table.where(lambda r: r['方案'] == 'A方案').columns['转化率'] group_b = table.where(lambda r: r['方案'] == 'B方案').columns['转化率'] t_stat, p_value = group_a.independent_t_test(group_b) print(f"A 方案平均转化率: {group_a.mean():.2f}%") print(f"B 方案平均转化率: {group_b.mean():.2f}%") print(f"t 统计量: {t_stat:.4f}") print(f"p 值: {p_value:.4f}") if p_value < 0.05: print("结论:两种方案转化率存在显著差异(p < 0.05)") else: print("结论:两种方案转化率无显著差异(p >= 0.05)")案例 4:股票收益率滚动统计
计算股票日收益率的 5 日移动平均和移动标准差:
import agate import agatestats agatestats.install() stock_data = [ ('2024-01-01', 100.0), ('2024-01-02', 102.5), ('2024-01-03', 101.0), ('2024-01-04', 103.8), ('2024-01-05', 105.2), ('2024-01-06', 104.0), ('2024-01-07', 106.5), ('2024-01-08', 108.0), ('2024-01-09', 107.2), ('2024-01-10', 109.5), ] table = agate.Table(stock_data, ['日期', '收盘价'], [agate.Text(), agate.Number()]) 计算日收益率 table = table.compute([ ('日收益率', agate.Formula(agate.Number(), lambda r: (r['收盘价'] - 100) / 100 * 100)) ]) price_col = table.columns['收盘价'] 计算 3 日移动平均 ma3 = price_col.moving_average(3) print("3 日移动平均收盘价:", [round(v, 2) for v in ma3]) 计算 3 日移动标准差 msd3 = price_col.moving_stdev(3) print("3 日移动标准差:", [round(v, 2) for v in msd3])案例 5:员工满意度调查分析
分析不同部门员工满意度得分的差异:
import agate import agatestats agatestats.install() survey_data = [ ('技术部', 85), ('技术部', 90), ('技术部', 78), ('技术部', 92), ('市场部', 75), ('市场部', 80), ('市场部', 72), ('市场部', 78), ('财务部', 88), ('财务部', 85), ('财务部', 90), ('财务部', 82), ] table = agate.Table(survey_data, ['部门', '满意度'], [agate.Text(), agate.Number()]) 分组统计 grouped = table.group_by('部门') dept_stats = grouped.aggregate([ ('平均满意度', agate.Mean('满意度')), ('满意度标准差', agate.Stdev('满意度')), ('最低满意度', agate.Min('满意度')), ('最高满意度', agate.Max('满意度')), ('人数', agate.Count()) ]) print("各部门满意度统计:") dept_stats.print_table(max_rows=20) 单因素 ANOVA 分析 tech = table.where(lambda r: r['部门'] == '技术部').columns['满意度'] market = table.where(lambda r: r['部门'] == '市场部').columns['满意度'] finance = table.where(lambda r: r['部门'] == '财务部').columns['满意度'] f_stat, p_value = tech.anova(market, finance) print(f"\nANOVA F 统计量: {f_stat:.4f}") print(f"ANOVA p 值: {p_value:.4f}") if p_value < 0.05: print("结论:不同部门满意度存在显著差异") else: print("结论:不同部门满意度无显著差异")案例 6:产品质量检测异常值分析
检测产品重量数据中的异常值:
import agate import agatestats agatestats.install() weight_data = [ ('产品1', 50.2), ('产品2', 49.8), ('产品3', 50.1), ('产品4', 50.0), ('产品5', 49.9), ('产品6', 50.3), ('产品7', 55.7), # 异常值 ('产品8', 50.1), ('产品9', 49.7), ('产品10', 50.0), ('产品11', 48.5), # 异常值 ('产品12', 50.2), ] table = agate.Table(weight_data, ['产品', '重量'], [agate.Text(), agate.Number()]) weight_col = table.columns['重量'] mean = weight_col.mean() std = weight_col.stdev() print(f"重量均值: {mean:.2f}g") print(f"重量标准差: {std:.4f}g") 使用 3-sigma 法则检测异常值 threshold = 3 * std print(f"\n异常值检测(3-sigma 法则,阈值: {threshold:.4f}g):") for row in table.rows: deviation = abs(row['重量'] - mean) if deviation > threshold: print(f" {row['产品']}: {row['重量']}g(偏差 {deviation:.2f}g,超出阈值)") else: print(f" {row['产品']}: {row['重量']}g(正常)")案例 7:气温数据趋势分析
分析某城市 12 个月的平均气温变化趋势:
import agate import agatestats agatestats.install() temp_data = [ ('1月', 2.0), ('2月', 4.5), ('3月', 9.0), ('4月', 15.0), ('5月', 20.5), ('6月', 25.0), ('7月', 28.0), ('8月', 27.5), ('9月', 23.0), ('10月', 17.0), ('11月', 10.0), ('12月', 4.0), ] table = agate.Table(temp_data, ['月份', '平均气温'], [agate.Text(), agate.Number()]) temp_col = table.columns['平均气温'] print(f"全年平均气温: {temp_col.mean():.1f}°C") print(f"气温中位数: {temp_col.median():.1f}°C") print(f"气温标准差: {temp_col.stdev():.1f}°C") print(f"气温偏度: {temp_col.skewness():.3f}") print(f"气温峰度: {temp_col.kurtosis():.3f}") 计算月份序号用于趋势分析 table = table.compute([ ('月份序号', agate.Formula(agate.Number(), lambda r: int(r['月份'].replace('月', '')))) ]) month_num = table.columns['月份序号'] correlation = month_num.pearson_correlation(temp_col) print(f"\n月份与气温 Pearson 相关系数: {correlation:.4f}") if correlation > 0: print("结论:气温随月份呈上升趋势(1-7月)") else: print("结论:气温随月份呈下降趋势(7-12月)")案例 8:电商用户行为分析
分析不同用户群体的购买行为差异:
import agate import agatestats agatestats.install() user_data = [ ('新用户', 1, 150.0), ('新用户', 1, 200.0), ('新用户', 2, 180.0), ('新用户', 1, 120.0), ('新用户', 1, 250.0), ('老用户', 5, 800.0), ('老用户', 3, 450.0), ('老用户', 4, 600.0), ('老用户', 6, 950.0), ('老用户', 3, 500.0), ('VIP用户', 10, 2000.0), ('VIP用户', 8, 1800.0), ('VIP用户', 12, 2500.0), ('VIP用户', 7, 1500.0), ('VIP用户', 9, 2200.0), ] table = agate.Table(user_data, ['用户类型', '购买次数', '总消费额'], [agate.Text(), agate.Number(), agate.Number()]) 计算客单价 table = table.compute([ ('客单价', agate.Formula(agate.Number(), lambda r: r['总消费额'] / r['购买次数'])) ]) 分组统计 grouped = table.group_by('用户类型') user_stats = grouped.aggregate([ ('平均购买次数', agate.Mean('购买次数')), ('平均总消费', agate.Mean('总消费额')), ('平均客单价', agate.Mean('客单价')), ('消费标准差', agate.Stdev('总消费额')), ('用户数', agate.Count()) ]) print("各用户类型行为统计:") user_stats.print_table(max_rows=20) 新用户与老用户消费差异 t 检验 new_users = table.where(lambda r: r['用户类型'] == '新用户').columns['总消费额'] old_users = table.where(lambda r: r['用户类型'] == '老用户').columns['总消费额'] t_stat, p_value = new_users.independent_t_test(old_users) print(f"\n新用户 vs 老用户消费 t 检验:") print(f"t 统计量: {t_stat:.4f}") print(f"p 值: {p_value:.4f}") if p_value < 0.05: print("结论:新用户与老用户消费存在显著差异") else: print("结论:新用户与老用户消费无显著差异")6. 常见错误与使用注意事项
6.1 常见错误
| 错误类型 | 错误信息 | 原因 | 解决方法 |
|---|---|---|---|
| 未注册扩展 | AttributeError: 'NumberColumn' object has no attribute 'mean' | 未调用agatestats.install() | 在使用统计方法前先执行agatestats.install() |
| 数据类型错误 | TypeError: unsupported operand type(s) | 对非数值列调用统计方法 | 确保目标列类型为agate.Number() |
| 数据量不足 | ValueError: need at least one value | 空列或数据行数不足 | 检查数据是否为空,确保有足够样本 |
| 缺失值处理 | ValueError: NaN values detected | 数据中包含 NaN 值 | 使用table.where()过滤或填充缺失值 |
| 分组键错误 | KeyError: '列名' | 分组列名不存在 | 确认列名拼写正确,区分大小写 |
6.2 使用注意事项
- 数据不可变性:agate 表格是不可变的,所有操作都返回新表格,不会修改原数据。如果需要修改,请将结果赋值给新变量。
- 内存管理:对于大型数据集,agate-stats 的统计计算会加载全部数据到内存,建议先对数据进行采样或分批处理。
- 统计假设检验前提:使用 t 检验、ANOVA 等参数检验前,应检查数据是否满足正态性和方差齐性假设。agate-stats 不自动检查这些前提条件,需要用户自行验证。
- 缺失值处理策略:agate-stats 的统计方法默认不处理缺失值。建议在计算前使用
table.where(lambda r: r['列名'] is not None)过滤缺失值。 - 版本兼容性:agate-stats 与 agate 主版本需要匹配。建议使用
pip install "agate-stats>=0.2.0"确保兼容性。 - 性能考量:对于超过 10 万行的大数据集,agate-stats 的性能可能不如 pandas。建议在数据量较大时考虑使用其他库。
- 结果解释:统计结果需要结合业务背景进行解释,避免机械套用统计结论。例如,相关性不等于因果关系。
- 滚动统计窗口:
moving_average()和moving_stdev()的窗口大小必须小于数据长度,否则会返回空列表。
7. 总结
agate-stats 是 agate 数据分析库的重要扩展,为 Python 开发者提供了简洁、易用的统计计算能力。通过本文的 8 个实际案例,可以看到 agate-stats 在销售分析、教育评估、A/B 测试、金融分析、员工调查、质量检测、气象分析和用户行为分析等场景中的广泛应用。掌握 agate-stats 的核心功能和使用注意事项,能够帮助数据分析师快速完成常见统计任务,提高工作效率。
《动手学PyTorch建模与应用:从深度学习到大模型》是一本从零基础上手深度学习和大模型的PyTorch实战指南。全书共11章,前6章涵盖深度学习基础,包括张量运算、神经网络原理、数据预处理及卷积神经网络等;后5章进阶探讨图像、文本、音频建模技术,并结合Transformer架构解析大语言模型的开发实践。书中通过房价预测、图像分类等案例讲解模型构建方法,每章附有动手练习题,帮助读者巩固实战能力。内容兼顾数学原理与工程实现,适配PyTorch框架最新技术发展趋势。