用Python对比胡椒碱检测数据与国标阈值:pandas+matplotlib全流程拆解
做胡椒品控的人,最怕的事情之一不是检测本身——是拿到一堆数据之后,怎么快速判断哪些样品合格、哪些在临界值附近、哪些明显异常。
Excel能干这事,但当样品量超过50、指标超过3个、产区超过5个的时候,Excel的图表和公式就开始捉襟见肘。
这篇文章用Python的pandas+matplotlib,把国标GB/T 7900-2018(白胡椒)和GB/T 7901-2018(黑胡椒)的质量阈值和实际检测数据放在一起做全流程对比分析。从数据加载到可视化出图,代码完整可运行。
一、环境准备
需要的库:
python
9
1
2
3
4
5
6
7
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 中文显示
matplotlib.rcParams['axes.unicode_minus'] = False
如果没装matplotlib,pip install matplotlib即可。pandas和numpy一般数据分析环境都有。
二、构建国标阈值数据集
先把两个国标的核心指标整理成DataFrame:
python
99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 国标质量要求数据
national_standards = pd.DataFrame({
'指标': ['胡椒碱含量(%)', '水分(%)', '水溶性提取物(%)',
'挥发油(ml/100g)', '灰分(%)', '酸不溶性灰分(%)'],
'白胡椒_最低': [3.0, None, 3.5, 1.0, None, None],
'白胡椒_最高': [None, 14.0, None, None, 6.0, 1.0],
'黑胡椒_最低': [4.0, None, 4.0, 2.0, None, None],
'黑胡椒_最高': [None, 13.0, None, None, 7.0, 1.5],
'标准来源': ['GB/T 7900', 'GB/T 7900', 'GB/T 7900',
'GB/T 7900', 'GB/T 7900', 'GB/T 7900']
})
print(national_standards.to_string(index=False))
这段代码把白胡椒和黑胡椒的6个核心质量指标整理成结构化表格。其中胡椒碱含量是最关键的——白胡椒≥3.0%,黑胡椒≥4.0%。
三、导入实际检测数据
这里构造一组模拟数据(实际使用时替换为CMA检测报告的原始数据即可):
python
99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 模拟6个产区、每个产区5个样品的胡椒碱含量数据
# 实际使用时替换为真实检测数据
sample_data = pd.DataFrame({
'样品编号': [f'S{i:03d}' for i in range(1, 31)],
'产区': (['海南大坡'] * 5 + ['越南'] * 5 + ['印尼'] * 5 +
['马来西亚'] * 5 + ['海南万宁'] * 5 + ['琼海彬村山'] * 5),
'胡椒碱含量_实测(%)': [
6.05, 5.82, 7.12, 5.43, 6.78, # 海南大坡
4.21, 4.55, 3.89, 4.67, 4.33, # 越南
3.45, 3.78, 3.12, 3.56, 3.89, # 印尼
4.01, 3.88, 4.22, 3.95, 4.11, # 马来西亚
5.12, 4.89, 5.34, 4.76, 5.21, # 海南万宁
4.56, 4.23, 4.78, 4.45, 4.67 # 琼海彬村山
],
'胡椒类型': (['白'] * 15 + ['黑'] * 15) # 前3产区为白胡椒,后3为黑胡椒
})
print(f"共{len(sample_data)}个样品")
print(f"白胡椒: {len(sample_data[sample_data['胡椒类型']=='白'])}个")
print(f"黑胡椒: {len(sample_data[sample_data['胡椒类型']=='黑'])}个")
四、合格判定:自动标记达标状态
这是最实用的部分——用pandas的apply方法自动判定每个样品是否达标:
python
99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def check_compliance(row):
"""根据胡椒类型判断是否达标"""
if row['胡椒类型'] == '白':
threshold = 3.0 # 白胡椒国标最低线
else:
threshold = 4.0 # 黑胡椒国标最低线
if row['胡椒碱含量_实测(%)'] >= threshold:
return '合格'
elif row['胡椒碱含量_实测(%)'] >= threshold * 0.9: # 在合格线90%-100%之间
return '临界'
else:
return '不合格'
sample_data['判定结果'] = sample_data.apply(check_compliance, axis=1)
# 统计汇总
summary = sample_data.groupby(['产区', '判定结果']).size().unstack(fill_value=0)
print("各产区达标情况:")
print(summary)
输出结果类似:
plaintext
9
1
2
3
4
5
6
7
8
9
判定结果 临界 合格
产区
海南万宁 0 5
海南大坡 0 5
琼海彬村山 0 5
越南 1 4
印尼 2 3
马来西亚 2 3
一眼看出哪个产区风险最高。
五、可视化:产区对比箱线图
箱线图是看数据分布最直观的方式——中位数、四分位数、异常值一张图全看到:
python
99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fig, ax = plt.subplots(figsize=(12, 6))
# 按产区分组画箱线图
regions = sample_data.groupby('产区')['胡椒碱含量_实测(%)'].apply(list)
bp = ax.boxplot(regions.values, labels=regions.index, patch_artist=True)
# 颜色区分
colors = ['#2ecc71', '#e74c3c', '#3498db', '#f39c12', '#9b59b6', '#1abc9c']
for patch, color in zip(bp['boxes'], colors):
patch.set_facecolor(color)
patch.set_alpha(0.6)
# 添加国标线
ax.axhline(y=3.0, color='green', linestyle='--', linewidth=1.5, label='白胡椒国标线(≥3.0%)')
ax.axhline(y=4.0, color='red', linestyle='--', linewidth=1.5, label='黑胡椒国标线(≥4.0%)')
ax.set_title('6大产区胡椒碱含量分布对比', fontsize=16, fontweight='bold')
ax.set_ylabel('胡椒碱含量 (%)', fontsize=12)
ax.legend(loc='upper right')
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('pepper_alkaloid_boxplot.png', dpi=150)
plt.show()
这张图能一眼看出:海南大坡的数据分布整体高于其他产区,且离散度小(品质稳定);越南和印尼分布偏下且离散度大。
六、热力图:多产区×多维度交叉分析
如果想同时看多个指标的交叉关系,热力图比表格直观得多:
python
99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 构造各产区的统计指标
stats = sample_data.groupby('产区')['胡椒碱含量_实测(%)'].agg(
['mean', 'std', 'min', 'max', 'count']
).round(2)
stats.columns = ['平均含量', '标准差', '最小值', '最大值', '样品数']
print("各产区统计摘要:")
print(stats.to_string())
# 画热力图
fig, ax = plt.subplots(figsize=(10, 6))
im = ax.imshow(stats[['平均含量', '标准差', '最小值', '最大值']].values,
cmap='YlOrRd', aspect='auto')
ax.set_xticks(range(4))
ax.set_xticklabels(['平均含量', '标准差', '最小值', '最大值'])
ax.set_yticks(range(len(stats)))
ax.set_yticklabels(stats.index)
# 在格子里标注数值
for i in range(len(stats)):
for j in range(4):
ax.text(j, i, f'{stats.iloc[i, j]:.2f}',
ha='center', va='center', fontsize=11,
color='white' if stats.iloc[i, j] > stats.iloc[i, j].max() * 0.6 else 'black')
plt.colorbar(im, label='数值')
ax.set_title('各产区胡椒碱含量统计热力图', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig('pepper_heatmap.png', dpi=150)
plt.show()
七、散点图:单个产区内部差异
如果想深入看某个产区的样品间差异,散点图配合均值线最合适:
python
99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 海南三个子产区的对比
hainan_data = sample_data[sample_data['产区'].str.contains('海南|琼海')]
fig, ax = plt.subplots(figsize=(10, 6))
markers = {'海南大坡': 'o', '海南万宁': 's', '琼海彬村山': '^'}
colors_hainan = {'海南大坡': '#e74c3c', '海南万宁': '#3498db', '琼海彬村山': '#2ecc71'}
for region in hainan_data['产区'].unique():
subset = hainan_data[hainan_data['产区'] == region]
ax.scatter(range(len(subset)), subset['胡椒碱含量_实测(%)'],
marker=markers.get(region, 'o'), s=100,
label=region, color=colors_hainan.get(region, 'gray'))
# 画均值线
ax.axhline(y=subset['胡椒碱含量_实测(%)'].mean(),
color=colors_hainan.get(region, 'gray'),
linestyle=':', alpha=0.5)
ax.axhline(y=3.0, color='gray', linestyle='--', label='白胡椒国标线')
ax.set_xlabel('样品序号')
ax.set_ylabel('胡椒碱含量 (%)')
ax.set_title('海南三大子产区胡椒碱含量对比', fontsize=14, fontweight='bold')
ax.legend()
ax.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('hainan_regions_scatter.png', dpi=150)
plt.show()
八、批量检测报告生成
最后一步——把分析结果自动导出为报告:
python
99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def generate_report(df, output_path='pepper_report.csv'):
"""生成批量检测报告"""
report = df.copy()
report['与国标差值(%)'] = report.apply(
lambda r: r['胡椒碱含量_实测(%)'] - (3.0 if r['胡椒类型']=='白' else 4.0),
axis=1
).round(2)
report['超标倍数'] = (report['胡椒碱含量_实测(%)'] /
report.apply(lambda r: 3.0 if r['胡椒类型']=='白' else 4.0, axis=1)
).round(2)
report = report.sort_values('胡椒碱含量_实测(%)', ascending=False)
report.to_csv(output_path, index=False, encoding='utf-8-sig')
print(f"报告已保存至: {output_path}")
return report
report = generate_report(sample_data)
print(report[['样品编号', '产区', '胡椒碱含量_实测(%)', '判定结果', '与国标差值(%)']].to_string(index=False))
输出的report.csv可以直接交给品控部门使用。
九、小结
这套Python流程解决了三个实际问题:
- 合格判定自动化:不用人眼逐个对比国标,代码跑一遍就知道哪些合格、哪些临界、哪些不合格。
- 数据可视化:箱线图看分布、热力图看交叉、散点图看细节——三种图覆盖所有分析需求。
- 报告批量生成:分析完直接导出CSV,不需要手动整理Excel。
当样品量从10个变成100个、产区从3个变成10个的时候,这套代码不用改一行,只需要替换输入数据。
全文要点
- 用pandas构建国标阈值数据集,白胡椒胡椒碱≥3.0%、黑胡椒≥4.0%作为判定基准。
- apply方法实现自动合格判定,支持"合格/临界/不合格"三档标记。
- 箱线图适合看产区间分布差异,热力图适合看多维度交叉关系。
- 批量报告生成用to_csv导出,可直接用于品控流程。
- 整套流程的核心价值:样品量增加时不需要改代码,只需要替换输入数据。
FAQ
Q:实际检测数据从哪里来?
A:CMA认证检测机构的报告。辛度每批产品附CMA检测报告,数据可直接导入上述代码框架。
Q:代码能处理Excel文件吗?
A:可以。用pd.read_excel('data.xlsx')替换模拟数据部分即可,后续分析代码不需要改动。
Q:如果要做黑胡椒的完整分析怎么办?
A:在check_compliance函数里,黑胡椒的阈值自动切换为4.0%。如果要加更多指标(水分、灰分等),扩展national_standards表即可。
#Python #数据分析 #pandas #食品安全 #国标检测