初始归档:健康管理资料库(大医网/药膳/体质监测/中医理论等12个资料集,7712个文件)
This commit is contained in:
commit
80ae3811cf
7712 files changed
+4628547
No files matched your search
@@ -0,0 +1,560 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
中华药膳全书资料库 - 深度挖掘分析脚本
|
||||
生成4个输出:
|
||||
1. 药膳功效聚类.json
|
||||
2. 食材药材共现网络.json
|
||||
3. 药膳-体质关联.json
|
||||
4. 药膳深度挖掘报告.md
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
from collections import defaultdict, Counter
|
||||
|
||||
BASE = "/home/songyi/Documents/ai_agent_scraper_study/data/中华药膳全书学做药膳不生病"
|
||||
|
||||
# ─── 加载数据 ───────────────────────────────────────
|
||||
def load_json(path):
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
|
||||
调理药膳 = load_json(f"{BASE}/01_来源数据/调理药膳.json")
|
||||
配方库 = load_json(f"{BASE}/01_来源数据/药膳配方库_recipes.json")
|
||||
中药表 = load_json(f"{BASE}/01_来源数据/药膳常用中药功能表.json")
|
||||
食物表 = load_json(f"{BASE}/01_来源数据/药膳常用食物功能表.json")
|
||||
|
||||
print(f"调理药膳: {len(调理药膳)}条")
|
||||
print(f"配方库: {len(配方库)}条")
|
||||
print(f"中药表: {len(中药表)}条")
|
||||
print(f"食物表: {len(食物表)}条")
|
||||
|
||||
# ─── 提取名称列表(用于最长前缀匹配) ─────────────
|
||||
中药名列表 = sorted([h['名称'] for h in 中药表 if h.get('名称')], key=len, reverse=True)
|
||||
食物名列表 = sorted([f['名称'] for f in 食物表 if f.get('名称')], key=len, reverse=True)
|
||||
|
||||
# 统一别名处理:一些常见别名/变体
|
||||
别名映射 = {
|
||||
'枸杞': '枸杞子',
|
||||
'杞子': '枸杞子',
|
||||
'意薏苡仁': '薏苡仁',
|
||||
'薏苡仁': '薏苡仁',
|
||||
'薏仁': '薏苡仁',
|
||||
'白萝ト': '白萝卜',
|
||||
'胡萝ト': '胡萝卜',
|
||||
'芝庥': '芝麻',
|
||||
'川穹': '川芎',
|
||||
'有郁李仁': '郁李仁',
|
||||
'土茯': '土茯苓',
|
||||
'枣': '大枣',
|
||||
'红枣': '大枣',
|
||||
'元肉': '龙眼肉',
|
||||
'桂圆': '龙眼肉',
|
||||
'田七': '三七',
|
||||
'淮山': '山药',
|
||||
'淮山药': '山药',
|
||||
'云苓': '茯苓',
|
||||
'川仲': '杜仲',
|
||||
}
|
||||
|
||||
# 扩充别名
|
||||
中药别名扩充 = {}
|
||||
for h in 中药表:
|
||||
name = h.get('名称','')
|
||||
if name:
|
||||
中药别名扩充[name] = name
|
||||
aliases = h.get('别名','')
|
||||
if aliases:
|
||||
for a in re.split(r'[、,,;;。.\s]', aliases):
|
||||
a = a.strip()
|
||||
if a and len(a) >= 2:
|
||||
中药别名扩充[a] = name
|
||||
|
||||
食物别名扩充 = {}
|
||||
for f in 食物表:
|
||||
name = f.get('名称','')
|
||||
if name:
|
||||
食物别名扩充[name] = name
|
||||
aliases = f.get('别名','')
|
||||
if aliases:
|
||||
for a in re.split(r'[、,,;;。.\s]', aliases):
|
||||
a = a.strip()
|
||||
if a and len(a) >= 2:
|
||||
食物别名扩充[a] = name
|
||||
|
||||
# 合并别名
|
||||
中药别名扩充.update(别名映射)
|
||||
食物别名扩充.update(别名映射)
|
||||
|
||||
# 构建最长前缀匹配函数
|
||||
def 最长前缀匹配(text, name_list, alias_map):
|
||||
"""在text中查找name_list中的名称(最长前缀匹配)"""
|
||||
found = set()
|
||||
if not text:
|
||||
return found
|
||||
for name in name_list:
|
||||
if name in text:
|
||||
found.add(name)
|
||||
continue
|
||||
# 尝试别名
|
||||
for alias, standard in alias_map.items():
|
||||
if standard == name and alias in text:
|
||||
found.add(name)
|
||||
break
|
||||
return found
|
||||
|
||||
def 匹配中药(text):
|
||||
return 最长前缀匹配(text or '', 中药名列表, 中药别名扩充)
|
||||
|
||||
def 匹配食物(text):
|
||||
return 最长前缀匹配(text or '', 食物名列表, 食物别名扩充)
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════
|
||||
# 输出1:药膳功效聚类分析
|
||||
# ═══════════════════════════════════════════════════════
|
||||
print("\n=== 输出1:药膳功效聚类分析 ===")
|
||||
|
||||
# 功效关键词体系(多级)
|
||||
功效关键词 = [
|
||||
'补气', '益气', '补中益气',
|
||||
'养血', '补血', '活血', '化瘀',
|
||||
'滋阴', '养阴', '生津',
|
||||
'健脾', '补脾', '温脾',
|
||||
'补肾', '益肾', '温肾', '壮阳',
|
||||
'养肝', '疏肝', '清肝', '平肝',
|
||||
'润肺', '清肺', '补肺', '止咳',
|
||||
'安神', '养心', '宁心',
|
||||
'清热', '解毒', '降火', '泻火',
|
||||
'祛湿', '利湿', '化湿', '渗湿',
|
||||
'化痰', '祛痰',
|
||||
'消食', '开胃', '导滞',
|
||||
'通便', '润肠',
|
||||
'祛风', '散寒', '温中',
|
||||
'明目', '乌发',
|
||||
'利水', '消肿',
|
||||
'降压', '降脂', '降糖',
|
||||
'强筋骨', '壮骨',
|
||||
'抗衰老', '延年',
|
||||
'固表', '固涩',
|
||||
'理气', '行气',
|
||||
'排毒', '养颜',
|
||||
]
|
||||
|
||||
def 提取功效(text):
|
||||
"""从文本中提取功效关键词"""
|
||||
found = set()
|
||||
if not text:
|
||||
return found
|
||||
for kw in 功效关键词:
|
||||
if kw in text:
|
||||
found.add(kw)
|
||||
return found
|
||||
|
||||
# 合并所有药膳数据
|
||||
所有药膳 = []
|
||||
for item in 调理药膳:
|
||||
所有药膳.append({
|
||||
'name': item.get('名称',''),
|
||||
'source': '调理药膳',
|
||||
'symptom': item.get('症状',''),
|
||||
'material': item.get('材料准备',''),
|
||||
'process': item.get('制作过程',''),
|
||||
'effect': item.get('功能效用',''),
|
||||
})
|
||||
for item in 配方库:
|
||||
所有药膳.append({
|
||||
'name': item.get('name',''),
|
||||
'source': '配方库',
|
||||
'category': item.get('category',''),
|
||||
'material': item.get('材料准备',''),
|
||||
'process': item.get('制作过程',''),
|
||||
'effect': item.get('功能效用',''),
|
||||
})
|
||||
|
||||
# 统计功效频率
|
||||
功效频率 = Counter()
|
||||
功效药膳集 = defaultdict(list) # 功效 -> [(name, source, effect)]
|
||||
|
||||
for item in 所有药膳:
|
||||
effects = 提取功效(item['effect'])
|
||||
effects |= 提取功效(item['material']) # 材料也可能有功效提示
|
||||
for kw in effects:
|
||||
功效频率[kw] += 1
|
||||
功效药膳集[kw].append({
|
||||
'name': item['name'],
|
||||
'source': item['source'],
|
||||
'effect': item['effect'][:100] + '...' if len(item.get('effect','')) > 100 else item.get('effect','')
|
||||
})
|
||||
|
||||
print(f"提取到 {len(功效频率)} 种功效关键词")
|
||||
for kw, cnt in 功效频率.most_common(20):
|
||||
print(f" {kw}: {cnt}")
|
||||
|
||||
# 共现分析:哪些功效常同时出现
|
||||
功效共现 = defaultdict(lambda: defaultdict(int))
|
||||
功效共现矩阵 = []
|
||||
|
||||
for item in 所有药膳:
|
||||
effects = list(提取功效(item['effect']) | 提取功效(item['material']))
|
||||
for i in range(len(effects)):
|
||||
for j in range(i+1, len(effects)):
|
||||
a, b = sorted([effects[i], effects[j]])
|
||||
功效共现[a][b] += 1
|
||||
|
||||
# 构建共现列表
|
||||
共现列表 = []
|
||||
for a in 功效共现:
|
||||
for b in 功效共现[a]:
|
||||
cnt = 功效共现[a][b]
|
||||
if cnt >= 2: # 过滤低频
|
||||
共现列表.append([a, b, cnt])
|
||||
共现列表.sort(key=lambda x: x[2], reverse=True)
|
||||
|
||||
print(f"功效共现对(>=2次): {len(共现列表)}")
|
||||
|
||||
# 每种功效的TOP10药膳
|
||||
功效TOP10 = {}
|
||||
for kw in 功效关键词:
|
||||
items = 功效药膳集.get(kw, [])
|
||||
# 去重
|
||||
seen = set()
|
||||
unique = []
|
||||
for it in items:
|
||||
key = it['name'] + it['source']
|
||||
if key not in seen:
|
||||
seen.add(key)
|
||||
unique.append(it)
|
||||
unique = unique[:10]
|
||||
if unique:
|
||||
功效TOP10[kw] = unique
|
||||
|
||||
# 组装输出1
|
||||
输出1 = {
|
||||
"功效频率统计": {kw: cnt for kw, cnt in 功效频率.most_common()},
|
||||
"功效共现分析": 共现列表,
|
||||
"功效关联药膳TOP10": {kw: items for kw, items in 功效TOP10.items()},
|
||||
"统计": {
|
||||
"总功效种类数": len(功效频率),
|
||||
"总药膳数": len(所有药膳),
|
||||
"高频率功效(>=20)": [{"功效": kw, "频次": cnt} for kw, cnt in 功效频率.most_common() if cnt >= 20]
|
||||
}
|
||||
}
|
||||
|
||||
with open(f"{BASE}/02_加工数据/药膳功效聚类.json", 'w', encoding='utf-8') as f:
|
||||
json.dump(输出1, f, ensure_ascii=False, indent=2)
|
||||
print("✓ 药膳功效聚类.json 写入完成")
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════
|
||||
# 输出2:食材-药材共现网络
|
||||
# ═══════════════════════════════════════════════════════
|
||||
print("\n=== 输出2:食材-药材共现网络 ===")
|
||||
|
||||
# 对所有药膳的材料准备字段做匹配
|
||||
单品频率 = Counter()
|
||||
共现对 = defaultdict(int)
|
||||
|
||||
for item in 所有药膳:
|
||||
material = item.get('material', '')
|
||||
herbs = 匹配中药(material)
|
||||
foods = 匹配食物(material)
|
||||
|
||||
# 单品频率
|
||||
for h in herbs:
|
||||
单品频率[h] += 1
|
||||
for f in foods:
|
||||
单品频率[f] += 1
|
||||
|
||||
# 共现对:药材-药材、药材-食物
|
||||
all_ingredients = list(herbs) + list(foods)
|
||||
for i in range(len(all_ingredients)):
|
||||
for j in range(i+1, len(all_ingredients)):
|
||||
a, b = sorted([all_ingredients[i], all_ingredients[j]])
|
||||
共现对[(a, b)] += 1
|
||||
|
||||
# 转换为输出格式
|
||||
共现对列表 = [[a, b, cnt] for (a, b), cnt in 共现对.items()]
|
||||
共现对列表.sort(key=lambda x: x[2], reverse=True)
|
||||
|
||||
# 过滤低频
|
||||
共现对列表_high = [p for p in 共现对列表 if p[2] >= 3]
|
||||
|
||||
输出2 = {
|
||||
"共现对": 共现对列表_high,
|
||||
"单品频率": {k: v for k, v in 单品频率.most_common()},
|
||||
"统计": {
|
||||
"总共现对数": len(共现对),
|
||||
"高频共现对(>=3次)": len(共现对列表_high),
|
||||
"总单品数": len(单品频率),
|
||||
"高频单品(>=10次)": [{"名称": k, "频次": v} for k, v in 单品频率.most_common() if v >= 10]
|
||||
}
|
||||
}
|
||||
|
||||
with open(f"{BASE}/02_加工数据/食材药材共现网络.json", 'w', encoding='utf-8') as f:
|
||||
json.dump(输出2, f, ensure_ascii=False, indent=2)
|
||||
print("✓ 食材药材共现网络.json 写入完成")
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════
|
||||
# 输出3:药膳-体质关联增强
|
||||
# ═══════════════════════════════════════════════════════
|
||||
print("\n=== 输出3:药膳-体质关联增强 ===")
|
||||
|
||||
九种体质关键字 = {
|
||||
"气虚质": ['补气','益气','黄芪','党参','白术','山药','大枣','气虚','乏力'],
|
||||
"阳虚质": ['温阳','散寒','生姜','肉桂','羊肉','韭菜','干姜','阳虚','畏寒'],
|
||||
"阴虚质": ['滋阴','润燥','百合','麦冬','沙参','玉竹','枸杞','阴虚','口干'],
|
||||
"痰湿质": ['化痰','祛湿','陈皮','茯苓','薏米','赤小豆','荷叶','痰湿','肥胖'],
|
||||
"湿热质": ['清热','利湿','绿豆','冬瓜','苦瓜','薏苡仁','湿热','口苦'],
|
||||
"血瘀质": ['活血','化瘀','山楂','红花','当归','川芎','玫瑰','血瘀','刺痛'],
|
||||
"气郁质": ['疏肝','理气','柴胡','香附','薄荷','玫瑰花','气郁','胸闷'],
|
||||
"特禀质": ['固表','祛风','黄芪','白术','防风','过敏','鼻塞','哮喘'],
|
||||
"平和质": ['平和','平衡','均衡','保健','养生','五谷杂粮'],
|
||||
}
|
||||
|
||||
# 一些同义词/别名映射用于体质匹配
|
||||
体质别名 = {
|
||||
'薏米': '薏苡仁',
|
||||
'杞子': '枸杞子',
|
||||
'红枣': '大枣',
|
||||
'桂圆': '龙眼肉',
|
||||
}
|
||||
|
||||
def 计算体质得分(item, keywords):
|
||||
"""计算一个药膳与某种体质的匹配得分"""
|
||||
score = 0
|
||||
reasons = []
|
||||
|
||||
fields = {
|
||||
'name': item.get('name',''),
|
||||
'material': item.get('material',''),
|
||||
'effect': item.get('effect',''),
|
||||
'symptom': item.get('symptom',''),
|
||||
}
|
||||
|
||||
text_all = ' '.join(fields.values())
|
||||
|
||||
for kw in keywords:
|
||||
# 直接匹配
|
||||
if kw in text_all:
|
||||
score += 2
|
||||
reasons.append(kw)
|
||||
continue
|
||||
# 尝试别名
|
||||
alias = 体质别名.get(kw)
|
||||
if alias and alias in text_all:
|
||||
score += 2
|
||||
reasons.append(kw)
|
||||
continue
|
||||
# 模糊匹配(部分匹配,针对复合词)
|
||||
# 如果关键字是2个字,放宽匹配
|
||||
if len(kw) == 2:
|
||||
if kw in text_all.replace(' ','').replace(',','').replace('、',''):
|
||||
score += 1
|
||||
reasons.append(kw)
|
||||
|
||||
return score, reasons
|
||||
|
||||
体质结果 = {}
|
||||
for 体质, keywords in 九种体质关键字.items():
|
||||
药膳得分列表 = []
|
||||
for item in 所有药膳:
|
||||
score, reasons = 计算体质得分(item, keywords)
|
||||
if score >= 2 and len(reasons) >= 1:
|
||||
药膳得分列表.append({
|
||||
'药膳名': item['name'],
|
||||
'来源': item['source'],
|
||||
'得分': score,
|
||||
'匹配理由': reasons[:6] # 最多6个
|
||||
})
|
||||
|
||||
# 按得分降序,取TOP50
|
||||
药膳得分列表.sort(key=lambda x: x['得分'], reverse=True)
|
||||
体质结果[体质] = 药膳得分列表[:50]
|
||||
|
||||
print(f" {体质}: {len(药膳得分列表)}条匹配")
|
||||
|
||||
输出3 = 体质结果
|
||||
|
||||
with open(f"{BASE}/02_加工数据/药膳-体质关联.json", 'w', encoding='utf-8') as f:
|
||||
json.dump(输出3, f, ensure_ascii=False, indent=2)
|
||||
print("✓ 药膳-体质关联.json 写入完成")
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════
|
||||
# 输出4:深度挖掘报告(Markdown)
|
||||
# ═══════════════════════════════════════════════════════
|
||||
print("\n=== 输出4:深度挖掘报告 ===")
|
||||
|
||||
# 分类类别统计(从配方库)
|
||||
分类统计 = Counter()
|
||||
for item in 配方库:
|
||||
cat = item.get('category', '未分类')
|
||||
分类统计[cat] += 1
|
||||
|
||||
# 体质TOP10
|
||||
体质TOP10输出 = {}
|
||||
for 体质 in 九种体质关键字:
|
||||
items = 输出3.get(体质, [])[:10]
|
||||
体质TOP10输出[体质] = items
|
||||
|
||||
# 功效TOP20
|
||||
功效TOP20 = 功效频率.most_common(20)
|
||||
|
||||
# 食材-药材高频共现TOP30
|
||||
共现TOP30 = 共现对列表_high[:30]
|
||||
|
||||
md = f"""# 中华药膳全书 - 深度挖掘分析报告
|
||||
|
||||
> 生成日期: 自动分析
|
||||
> 数据来源: 中华药膳全书学做药膳不生病资料库
|
||||
|
||||
---
|
||||
|
||||
## 一、数据概览
|
||||
|
||||
| 数据源 | 记录数 |
|
||||
|--------|--------|
|
||||
| 调理药膳 | {len(调理药膳)} 条 |
|
||||
| 药膳配方库 | {len(配方库)} 条 |
|
||||
| 中药功能表 | {len(中药表)} 种 |
|
||||
| 食物功能表 | {len(食物表)} 种 |
|
||||
| 合并药膳总数 | {len(所有药膳)} 条 |
|
||||
|
||||
---
|
||||
|
||||
## 二、药膳分类类别统计
|
||||
|
||||
| 分类 | 数量 |
|
||||
|------|------|
|
||||
"""
|
||||
|
||||
for cat, cnt in 分类统计.most_common():
|
||||
md += f"| {cat} | {cnt} |\n"
|
||||
|
||||
md += f"""
|
||||
|
||||
---
|
||||
|
||||
## 三、药膳功效聚类 TOP20
|
||||
|
||||
| 排名 | 功效关键词 | 出现频次 |
|
||||
|------|-----------|---------|
|
||||
"""
|
||||
|
||||
for i, (kw, cnt) in enumerate(功效TOP20, 1):
|
||||
md += f"| {i} | {kw} | {cnt} |\n"
|
||||
|
||||
md += f"""
|
||||
|
||||
### 功效共现分析(高频共现对 TOP20)
|
||||
|
||||
功效共现分析揭示哪些功效常在同一道药膳中同时出现:
|
||||
|
||||
| 排名 | 功效A | 功效B | 共现次数 |
|
||||
|------|-------|-------|---------|
|
||||
"""
|
||||
|
||||
for i, (a, b, cnt) in enumerate(共现列表[:20], 1):
|
||||
md += f"| {i} | {a} | {b} | {cnt} |\n"
|
||||
|
||||
md += """
|
||||
|
||||
---
|
||||
|
||||
## 四、食材-药材高频共现 TOP30
|
||||
|
||||
| 排名 | 食材/药材1 | 食材/药材2 | 共现次数 |
|
||||
|------|-----------|-----------|---------|
|
||||
"""
|
||||
|
||||
for i, (a, b, cnt) in enumerate(共现TOP30, 1):
|
||||
md += f"| {i} | {a} | {b} | {cnt} |\n"
|
||||
|
||||
md += """
|
||||
|
||||
### 高频单品 TOP20
|
||||
|
||||
| 排名 | 食材/药材 | 使用频次 |
|
||||
|------|-----------|---------|
|
||||
"""
|
||||
|
||||
for i, (k, v) in enumerate(单品频率.most_common(20), 1):
|
||||
md += f"| {i} | {k} | {v} |\n"
|
||||
|
||||
md += """
|
||||
|
||||
---
|
||||
|
||||
## 五、各类体质推荐药膳 TOP10
|
||||
|
||||
"""
|
||||
|
||||
for 体质, items in 体质TOP10输出.items():
|
||||
md += f"""### {体质}
|
||||
|
||||
| 序号 | 药膳名称 | 来源 | 匹配得分 | 匹配理由 |
|
||||
|------|----------|------|---------|---------|
|
||||
"""
|
||||
for i, it in enumerate(items, 1):
|
||||
reasons = '、'.join(it['匹配理由'][:4])
|
||||
md += f"| {i} | {it['药膳名']} | {it['来源']} | {it['得分']} | {reasons} |\n"
|
||||
md += "\n"
|
||||
|
||||
md += """
|
||||
|
||||
---
|
||||
|
||||
## 六、分析结论
|
||||
|
||||
### 6.1 功效分布特征
|
||||
|
||||
"""
|
||||
# 找最高频的3个功效
|
||||
top3_eff = 功效频率.most_common(3)
|
||||
if len(top3_eff) >= 1:
|
||||
md += f"- 最高频功效关键词为「{top3_eff[0][0]}」({top3_eff[0][1]}次),其次为「{top3_eff[1][0]}」({top3_eff[1][1]}次)、「{top3_eff[2][0]}」({top3_eff[2][1]}次)\n"
|
||||
md += f"- 共提取到 {len(功效频率)} 种不同功效关键词,{len(共现列表)} 组有效共现对\n"
|
||||
|
||||
# 找最高频共现
|
||||
if 共现列表:
|
||||
top_co = 共现列表[0]
|
||||
md += f"- 功效共现组合中最引人注目的是「{top_co[0]}+{top_co[1]}」({top_co[2]}次),反映了药膳配伍中的经典搭配\n"
|
||||
|
||||
md += """
|
||||
|
||||
### 6.2 食材-药材配伍规律
|
||||
|
||||
"""
|
||||
if 共现对列表_high:
|
||||
top_pair = 共现对列表_high[0]
|
||||
md += f"- 最高频食材-药材搭配为「{top_pair[0]}+{top_pair[1]}」({top_pair[2]}次)\n"
|
||||
if len(共现对列表_high) >= 2:
|
||||
top_pair2 = 共现对列表_high[1]
|
||||
md += f"- 其次为「{top_pair2[0]}+{top_pair2[1]}」({top_pair2[2]}次)\n"
|
||||
if len(单品频率) >= 1:
|
||||
top_single = 单品频率.most_common(1)[0]
|
||||
md += f"- 使用频率最高的单品是「{top_single[0]}」({top_single[1]}次)\n"
|
||||
md += f"- 共发现 {len(共现对)} 组食材-药材共现关系,{len(单品频率)} 种单品\n"
|
||||
|
||||
md += """
|
||||
|
||||
### 6.3 体质匹配覆盖
|
||||
|
||||
"""
|
||||
for 体质 in 九种体质关键字:
|
||||
cnt = len(体质结果.get(体质, []))
|
||||
md += f"- {体质}:匹配到 {cnt} 道药膳\n"
|
||||
|
||||
md += """
|
||||
---
|
||||
|
||||
*报告完毕*
|
||||
"""
|
||||
|
||||
with open(f"{BASE}/04_分析报告/药膳深度挖掘报告.md", 'w', encoding='utf-8') as f:
|
||||
f.write(md)
|
||||
print("✓ 药膳深度挖掘报告.md 写入完成")
|
||||
|
||||
print("\n🎉 所有分析输出已完成!")
|
||||
Reference in new issue
Block a user