CHNS膳食数据清洗实战:从家庭到个人的营养摄入精准计算

张开发
2026/4/18 5:59:51 15 分钟阅读

分享文章

CHNS膳食数据清洗实战:从家庭到个人的营养摄入精准计算
1. CHNS膳食数据清洗的核心挑战中国健康与营养调查CHNS作为国内持续时间最长的营养流行病学研究之一其膳食数据具有典型的双轨制特征——既包含家庭食物称重记录又涵盖个人24小时膳食回顾。我在处理2011年波次数据时曾遇到一个典型案例某家庭连续3天记录的食用油消耗量为150g但成员个人回顾数据中脂肪摄入量却显著偏低。这种家庭与个人数据不匹配的现象正是膳食调查数据清洗需要解决的首要问题。膳食编码系统的代际差异是另一大痛点。CHNS项目跨越30余年期间经历了1991、2002、2004三个版本的**食物成分表FCT**更迭。比如2004年波次数据中马铃薯的编码可能是010101FCT 1991标准或011101FCT 2004标准。若不进行标准化处理直接计算营养素会导致严重偏差。这里分享一个实用技巧用R语言的stringr::str_pad()函数统一补全6位编码library(stringr) food_intake$foodcode_std - str_pad(food_intake$FOODCODE, width 6, side left, pad 0)2. 个人膳食数据的精细处理个人24小时回顾数据通常以SAS格式存储如nutr3_00.sas7bdat处理时要注意三个关键维度2.1 数据过滤与验证剔除无效记录删除食物重量为0或缺失的条目验证个体唯一性确保IDind与调查波次(WAVE)组合唯一典型错误示例2015年某研究发现未过滤异常值会导致蛋白质摄入量被高估30%2.2 营养素计算流程匹配食物成分表建议使用dplyr::left_join()合并数据单位转换特别注意脂肪酸等以百分比计量的成分三日平均计算需按个体ID和波次分组求均值nutr3_clean - nutr3_raw %% filter(!is.na(FOODCODE), V39 0) %% mutate(nutrient_energy (ENERGY_kcal/100)*V39) %% group_by(IDind, WAVE) %% summarise(avg_energy mean(nutrient_energy)/3)3. 家庭食物称重的转换艺术家庭数据nutr1_00.sas7bdat的特殊性在于记录的是全家总消耗量需要按人日数(person-days)分配到个体典型场景5口之家3天消耗大米2000g实际参与就餐人日数为12则人均日消耗量为166.67g处理流程中的关键步骤异常值处理将负值或极端大值替换为0营养素计算先计算家庭总摄入量再按人日数分配数据验证检查家庭与个人数据逻辑一致性home_nutrient - df_home %% mutate(jtcd ifelse(jtcd 0, 0, jtcd), fat_per100g 脂肪酸Total * jtcd / 100) %% group_by(hhid_WAVE) %% summarise(total_fat sum(fat_per100g)) %% left_join(nutr2_persondays, by hhid_WAVE) %% mutate(fat_per_person total_fat * jun / 3)4. 数据合并的黄金法则当个人与家庭数据需要合并时建议采用三层验证法编码一致性检查确保食物编码系统完全匹配营养素范围验证设置合理阈值如成人日能量摄入500-5000kcal逻辑关系校验家庭数据营养素总量应≥个人数据总和合并操作示例final_data - personal_nutrient %% full_join(home_nutrient, by IDind_WAVE) %% mutate( energy_final ifelse(is.na(d3kcal), avg_energy, d3kcal), flag case_when( abs(avg_energy - d3kcal) 1000 ~ 需复核, is.na(d3kcal) ~ 仅个人数据, TRUE ~ 数据一致 ) )实际项目中我发现约15%的个案需要人工复核。建议输出核查清单write.xlsx( filter(final_data, flag 需复核), 需要复核的异常个案.xlsx )5. 实战中的避坑指南5.1 编码转换陷阱2004版FCT中粳米编码为011101而2002版为011001解决方案建立跨版本映射表5.2 单位混淆问题脂肪酸数据可能同时存在g/100g和%两种单位处理建议统一转换为毫克每百克(mg/100g)5.3 缺失值处理策略对于5%的随机缺失可采用同类食物均值填补系统性缺失如某类食物完全未检测应保留NA并标注我曾处理过一个包含2000个家庭的数据集最初因忽略单位统一导致钙摄入量被低估40%。后来通过建立标准化的预处理流程将数据清洗时间从2周缩短到3天。关键是把所有转换规则封装成函数clean_nutrient - function(raw_data, fct_version) { # 单位标准化 if(fct_version 2004) { raw_data - mutate(raw_data, calcium_mg 钙.Ca..mg. * 10) # 原数据为mg/100g } # 更多处理规则... return(raw_data) }

更多文章