输入宠物每日喂食和运动数据,判断宠物是否超重,给出科学喂养方案。

20 阅读8分钟

我将为您创建一个完整的宠物健康管理程序,用于分析宠物的喂食和运动数据,判断是否超重并提供科学的喂养建议。

项目结构

pet_health_manager/ ├── main.py # 主程序入口 ├── pet_data_manager.py # 数据管理模块 ├── health_analyzer.py # 健康分析模块 ├── nutrition_planner.py # 营养规划模块 ├── utils.py # 工具函数 ├── config.py # 配置文件 ├── data/ # 数据存储目录 │ ├── pets.json # 宠物基本信息 │ └── records.csv # 日常记录数据 ├── README.md # 使用说明 └── requirements.txt # 依赖包列表

  1. requirements.txt

pandas==2.0.3 numpy==1.24.3 matplotlib==3.7.2 seaborn==0.12.2 openpyxl==3.1.2 datetime json os random

  1. config.py

""" 配置文件 - 定义宠物健康管理的默认参数和标准 """

宠物类型配置

PET_TYPES = { 'dog': { 'small': {'weight_range': (1, 10), 'activity_level': 'medium'}, 'medium': {'weight_range': (10, 25), 'activity_level': 'high'}, 'large': {'weight_range': (25, 45), 'activity_level': 'high'} }, 'cat': { 'small': {'weight_range': (2, 4), 'activity_level': 'medium'}, 'medium': {'weight_range': (4, 6), 'activity_level': 'low'}, 'large': {'weight_range': (6, 10), 'activity_level': 'low'} } }

标准热量需求 (kcal/天)

BASE_CALORIES = { 'dog': { 'small': 300, 'medium': 500, 'large': 800 }, 'cat': { 'small': 200, 'medium': 250, 'large': 300 } }

活动系数

ACTIVITY_FACTORS = { 'low': 0.8, # 低活动量 'medium': 1.0, # 中等活动量 'high': 1.2 # 高活动量 }

超重判断阈值 (BMI)

OVERWEIGHT_THRESHOLDS = { 'dog': 0.9, # BMI超过标准90%为超重 'cat': 0.85 # 猫的标准更严格 }

体重指数计算公式系数

BMI_COEFFICIENTS = { 'dog': {'a': 1.2, 'b': 1.0}, 'cat': {'a': 1.0, 'b': 1.0} }

数据存储路径

DATA_PATHS = { 'pets_file': 'data/pets.json', 'records_file': 'data/records.csv' }

  1. utils.py

""" 工具函数模块 - 包含数据处理和计算的辅助函数 """

import json import pandas as pd import numpy as np from datetime import datetime, timedelta import os from typing import Dict, List, Tuple, Optional

def ensure_data_directory(): """确保数据目录存在""" os.makedirs('data', exist_ok=True)

def load_pet_data() -> Dict: """ 加载宠物基本信息数据

Returns:
    宠物数据字典
"""
ensure_data_directory()
pets_file = 'data/pets.json'

if os.path.exists(pets_file):
    try:
        with open(pets_file, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        print(f"加载宠物数据失败: {e}")
        return {}
else:
    # 返回示例数据
    sample_data = {
        "1": {
            "name": "旺财",
            "type": "dog",
            "breed": "金毛",
            "birth_date": "2020-05-15",
            "gender": "male",
            "ideal_weight": 28.5,
            "notes": "活泼好动,喜欢跑步"
        },
        "2": {
            "name": "咪咪",
            "type": "cat",
            "breed": "英短",
            "birth_date": "2019-08-20",
            "gender": "female",
            "ideal_weight": 4.2,
            "notes": "比较懒,不爱运动"
        }
    }
    save_pet_data(sample_data)
    return sample_data

def save_pet_data(data: Dict) -> bool: """ 保存宠物基本信息数据

Args:
    data: 宠物数据字典
    
Returns:
    保存是否成功
"""
ensure_data_directory()
pets_file = 'data/pets.json'

try:
    with open(pets_file, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    return True
except Exception as e:
    print(f"保存宠物数据失败: {e}")
    return False

def load_records_data() -> pd.DataFrame: """ 加载日常记录数据

Returns:
    记录数据的DataFrame
"""
ensure_data_directory()
records_file = 'data/records.csv'

if os.path.exists(records_file):
    try:
        return pd.read_csv(records_file, parse_dates=['date'])
    except Exception as e:
        print(f"加载记录数据失败: {e}")
        return pd.DataFrame()
else:
    # 创建空的DataFrame结构
    columns = ['pet_id', 'date', 'food_amount', 'food_type', 
              'exercise_duration', 'exercise_type', 'weight', 'notes']
    df = pd.DataFrame(columns=columns)
    df['date'] = pd.to_datetime(df['date'])
    save_records_data(df)
    return df

def save_records_data(df: pd.DataFrame) -> bool: """ 保存日常记录数据

Args:
    df: 记录数据的DataFrame
    
Returns:
    保存是否成功
"""
ensure_data_directory()
records_file = 'data/records.csv'

try:
    df.to_csv(records_file, index=False, encoding='utf-8')
    return True
except Exception as e:
    print(f"保存记录数据失败: {e}")
    return False

def calculate_age(birth_date_str: str) -> int: """ 计算宠物年龄(以月为单位)

Args:
    birth_date_str: 出生日期字符串 (YYYY-MM-DD)
    
Returns:
    年龄(月)
"""
try:
    birth_date = datetime.strptime(birth_date_str, '%Y-%m-%d')
    today = datetime.now()
    age_months = (today.year - birth_date.year) * 12 + (today.month - birth_date.month)
    return max(0, age_months)
except Exception as e:
    print(f"计算年龄失败: {e}")
    return 0

def calculate_bmi(pet_type: str, weight: float, ideal_weight: float) -> float: """ 计算宠物体重指数 (BMI)

Args:
    pet_type: 宠物类型
    weight: 当前体重
    ideal_weight: 理想体重
    
Returns:
    BMI值
"""
if ideal_weight <= 0:
    return 0

# 简化的BMI计算,实际应用中可能需要更复杂的公式
bmi = weight / ideal_weight
return bmi

def get_date_range(days: int = 7) -> Tuple[datetime, datetime]: """ 获取日期范围

Args:
    days: 天数
    
Returns:
    开始日期和结束日期
"""
end_date = datetime.now()
start_date = end_date - timedelta(days=days)
return start_date, end_date

def validate_input_data(data: Dict) -> bool: """ 验证输入数据的有效性

Args:
    data: 输入数据字典
    
Returns:
    数据是否有效
"""
required_fields = ['pet_id', 'date', 'food_amount', 'exercise_duration', 'weight']

for field in required_fields:
    if field not in data or data[field] is None:
        return False

# 验证数值范围
if data['food_amount'] <= 0 or data['exercise_duration'] < 0 or data['weight'] <= 0:
    return False

return True

4. pet_data_manager.py

""" 宠物数据管理模块 - 负责宠物信息和记录的增删改查 """

import pandas as pd from typing import Dict, List, Optional from datetime import datetime, timedelta from utils import * from config import DATA_PATHS

class PetDataManager: """宠物数据管理器"""

def __init__(self):
    self.pets_data = load_pet_data()
    self.records_df = load_records_data()

def add_pet(self, pet_info: Dict) -> bool:
    """
    添加新宠物
    
    Args:
        pet_info: 宠物信息字典
        
    Returns:
        添加是否成功
    """
    try:
        # 生成唯一ID
        pet_id = str(max([int(id) for id in self.pets_data.keys()] + [0]) + 1)
        
        # 验证必需字段
        required_fields = ['name', 'type', 'breed', 'birth_date', 'gender', 'ideal_weight']
        for field in required_fields:
            if field not in pet_info:
                raise ValueError(f"缺少必需字段: {field}")
        
        # 添加创建时间
        pet_info['created_at'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        pet_info['age_months'] = calculate_age(pet_info['birth_date'])
        
        self.pets_data[pet_id] = pet_info
        return save_pet_data(self.pets_data)
        
    except Exception as e:
        print(f"添加宠物失败: {e}")
        return False

def update_pet(self, pet_id: str, pet_info: Dict) -> bool:
    """
    更新宠物信息
    
    Args:
        pet_id: 宠物ID
        pet_info: 新的宠物信息
        
    Returns:
        更新是否成功
    """
    try:
        if pet_id not in self.pets_data:
            raise ValueError(f"宠物ID {pet_id} 不存在")
        
        # 更新年龄
        if 'birth_date' in pet_info:
            pet_info['age_months'] = calculate_age(pet_info['birth_date'])
        
        self.pets_data[pet_id].update(pet_info)
        return save_pet_data(self.pets_data)
        
    except Exception as e:
        print(f"更新宠物信息失败: {e}")
        return False

def delete_pet(self, pet_id: str) -> bool:
    """
    删除宠物
    
    Args:
        pet_id: 宠物ID
        
    Returns:
        删除是否成功
    """
    try:
        if pet_id not in self.pets_data:
            raise ValueError(f"宠物ID {pet_id} 不存在")
        
        del self.pets_data[pet_id]
        return save_pet_data(self.pets_data)
        
    except Exception as e:
        print(f"删除宠物失败: {e}")
        return False

def get_pet_info(self, pet_id: str) -> Optional[Dict]:
    """
    获取宠物信息
    
    Args:
        pet_id: 宠物ID
        
    Returns:
        宠物信息字典
    """
    return self.pets_data.get(pet_id)

def list_all_pets(self) -> Dict:
    """
    获取所有宠物列表
    
    Returns:
        所有宠物信息
    """
    return self.pets_data

def add_record(self, record: Dict) -> bool:
    """
    添加日常记录
    
    Args:
        record: 记录信息字典
        
    Returns:
        添加是否成功
    """
    try:
        # 验证数据
        if not validate_input_data(record):
            raise ValueError("输入数据无效")
        
        # 确保日期格式正确
        if isinstance(record['date'], str):
            record['date'] = pd.to_datetime(record['date'])
        
        # 创建新的记录行
        new_record = pd.DataFrame([record])
        
        # 合并到现有数据
        if self.records_df.empty:
            self.records_df = new_record
        else:
            self.records_df = pd.concat([self.records_df, new_record], ignore_index=True)
        
        return save_records_data(self.records_df)
        
    except Exception as e:
        print(f"添加记录失败: {e}")
        return False

def get_pet_records(self, pet_id: str, days: int = 30) -> pd.DataFrame:
    """
    获取指定宠物的记录
    
    Args:
        pet_id: 宠物ID
        days: 获取最近多少天的记录
        
    Returns:
        记录DataFrame
    """
    if self.records_df.empty:
        return pd.DataFrame()
    
    # 筛选指定宠物的记录
    pet_records = self.records_df[self.records_df['pet_id'] == pet_id].copy()
    
    if pet_records.empty:
        return pd.DataFrame()
    
    # 筛选日期范围
    start_date, end_date = get_date_range(days)
    pet_records = pet_records[
        (pet_records['date'] >= start_date) & 
        (pet_records['date'] <= end_date)
    ]
    
    # 按日期排序
    pet_records = pet_records.sort_values('date', ascending=False)
    
    return pet_records

def get_latest_weight(self, pet_id: str) -> Optional[float]:
    """
    获取宠物最新体重
    
    Args:
        pet_id: 宠物ID
        
    Returns:
        最新体重,如果没有记录则返回None
    """
    records = self.get_pet_records(pet_id, days=365)  # 查找一年的记录
    
    if records.empty:
        return None
    
    latest_record = records.iloc[0]
    return latest_record['weight']

def get_average_food_intake(self, pet_id: str, days: int = 7) -> float:
    """
    获取平均食物摄入量
    
    Args:
        pet_id: 宠物ID
        days: 天数
        
    Returns:
        平均每天食物摄入量
    """
    records = self.get_pet_records(pet_id, days)
    
    if records.empty:
        return 0.0
    
    return records['food_amount'].mean()

def get_average_exercise(self, pet_id: str, days: int = 7) -> float:
    """
    获取平均运动量
    
    Args:
        pet_id: 宠物ID
        days: 天数
        
    Returns:
        平均每天运动时间(分钟)
    """
    records = self.get_pet_records(pet_id, days)
    
    if records.empty:
        return 0.0
    
    return records['exercise_duration'].mean()

5. health_analyzer.py

""" 健康分析模块 - 分析宠物健康状况,判断是否超重 """

import pandas as pd import numpy as np from typing import Dict, Tuple, List from datetime import datetime, timedelta from utils import * from config import *

class HealthAnalyzer: """宠物健康分析器"""

def __init__(self, data_manager: PetDataManager):
    self.data_manager = data_manager

def analyze_weight_status(self, pet_id: str) -> Dict:
    """
    分析宠物体重状态
    
    Args:
        pet_id: 宠物ID
        
    Returns:
        分析结果字典
    """
    pet_info = self.data_manager.get_pet_info(pet_id)
    if not pet_info:
        return {"error": "宠物信息不存在"}
    
    current_weight = self.data_manager.get_latest_weight(pet_id)
    if current_weight is None:
        return {"error": "没有体重记录"}
    
    ideal_weight = pet_info['ideal_weight']
    pet_type = pet_info['type']
    
    # 计算BMI
    bmi = calculate_bmi(pet_type, current_weight, ideal_weight)
    
    # 判断是否超重
    threshold = OVERWEIGHT_THRESHOLDS.get(pet_type, 0.9)
    is_overweight = bmi > threshold
    
    # 计算体重偏差百分比
    weight_diff_percent = ((current_weight - ideal_weight) / ideal_weight) * 100
    
    # 健康状态评级
    if abs(weight_diff_percent) <= 5:
        status = "理想"
        status_color = "green"
    elif weight_diff_percent > 5:
        status = "超重"
        status_color = "red"
    else:
        status = "偏瘦"
        status_color = "orange"
    
    analysis_result = {
        "pet_name": pet_info['name'],
        "pet_type": pet_type,
        "current_weight": round(current_weight, 2),
        "ideal_weight": ideal_weight,
        "weight_difference": round(current_weight - ideal_weight, 2),
        "weight_diff_percent": round(weight_diff_percent, 1),
        "bmi": round(bmi, 3),
        "threshold": threshold,
        "is_overweight": is_overweight,
        "status": status,
        "status_color": status_color,
        "analysis_date": datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    }
    
    return analysis_result

def analyze_food_intake(self, pet_id: str, days: int = 7) -> Dict:
    """
    分析食物摄入情况
    
    Args:
        pet_id: 宠物ID
        days: 分析天数
        
    Returns:
        食物摄入分析结果
    """
    pet_info = self.data_manager.get_pet_info(pet_id)
    if not pet_info:
        return {"error": "宠物信息不存在"}
    
    average_food = self.data_manager.get_average_food_intake(pet_id, days)
    if average_food == 0:
        return {"error": "没有足够的食物摄入记录"}
    
    # 计算推荐食物量
    recommended_food = self.calculate_recommended_food(pet_id)
    
    # 分析摄入情况
    food_ratio = average_food / recommended_food if recommended_food > 0 else 0
    
    if food_ratio < 0.8:
        food_status = "摄入不足"
        food_advice = "适当增加食物分量"
    elif food_ratio > 1.2:
        food_status = "摄入过量"
        food_advice = "适当减少食物分量"
    else:
        food_status = "摄入正常"
        food_advice = "保持当前饮食量"
    
    analysis_result = {
        "average_daily_food": round(average_food, 1),
        "recommended_food": round(recommended_food, 1),
        "food_ratio": round(food_ratio, 2),
        "food_status": food_status,
        "advice": food_advice,
        "analysis_days": days
    }
    
    return analysis_result

def analyze_exercise(self, pet_id: str, days: int = 7) -> Dict:
    """
    分析运动情况
    
    Args:
        pet_id: 宠物ID
        days: 分析天数
        
    Returns:
        运动分析结果
    """
    pet_info = self.data_manager.get_pet_info(pet_id)
    if not pet_info:
        return {"error": "宠物信息不存在"}
    
    average_exercise = self.data_manager.get_average_exercise(pet_id, days)
    if average_exercise == 0:
        return {"error": "没有足够的运动记录"}
    
    # 根据宠物类型和年龄推荐运动量
    recommended_exercise = self.calculate_recommended_exercise(pet_id)
    
    # 分析运动情况
    exercise_ratio = average_exercise / recommended_exercise if recommended_exercise > 0 else 0
    
    if exercise_ratio < 0.7:
        exercise_status = "运动不足"
        exercise_advice = "增加日常运动量,多散步或游戏"
    elif exercise_ratio > 1.3:
        exercise_status = "运动充足"
        exercise_advice = "运动量合适,继续保持"
    else:
        exercise_status = "运动适中"
        exercise_advice = "运动量基本合适"
    
    analysis_result = {
        "average_daily_exercise": round(average_exercise, 1),
        "recommended_exercise": round(recommended_exercise, 1),
        "exercise_ratio": round(exercise_ratio, 2),
        "exercise_status": exercise_status,
        "advice": exercise_advice,
        "analysis_days": days
    }
    
    return analysis_result

def calculate_recommended_food(self, pet_id: str) -> float:
    """
    计算推荐食物量
    
    Args:
        pet_id: 宠物ID
        
    Returns:
        推荐每日食物量(克)
    """
    pet_info = self.data_manager.get_pet_info(pet_id)
    if not pet_info:
        return 0
    
    pet_type = pet_info['type']
    breed = pet_info['breed']
    age_months = pet_info.get('age_months', 12)
    
    # 确定体型分类
    weight = pet_info['ideal_weight']
    size_category = self._determine_size_category(pet_type, weight)
    
    # 获取基础热量需求
    base_calories = BASE_CALORIES.get(pet_type, {}).get(size_category, 300)
    
    # 根据年龄调整
    if age_months < 12:  # 幼年期
        age_factor = 1.5 if pet_type == 'dog' else 2.0
    elif age_months < 84:  # 成年期
        age_factor = 1.0
    else:  # 老年期
        age_factor = 0.8
    
    # 根据活动水平调整(简化处理)
    activity_factor = ACTIVITY_FACTORS.get('medium', 1.0)
    
    # 计算总热量需求
    total_calories = base_calories * age_factor * activity_factor
    
    # 转换为食物重量(假设食物热量密度为4 kcal/g)
    food_amount = total_calories / 4
    
    return food_amount

def calculate_recommended_exercise(self, pet_id: str) -> float:
    """
    计算推荐运动量
    
    Args:
        pet_id: 宠物ID
        
    Returns:
        推荐每日运动时间(分钟)
    """
    pet_info = self.data_manager.get_pet_info(pet_id)
    if not pet_info:
        return 0
    
    pet_type = pet_info['type']
    age_months = pet_info.get('age_months', 12)
    
    # 基础运动量
    if pet_type == 'dog':
        if age_months < 12:  # 幼犬
            base_exercise = 30
        elif age_months < 84:  # 成犬
            base_exercise = 60
        else:  # 老犬
            base_exercise = 40
    else:  # 猫
        if age_months < 12:  # 幼猫
            base_exercise = 20
        elif age_months < 120:  # 成猫
            base_exercise = 30
        else:  # 老猫
            base_exercise = 20
    
    return base_exercise

def _determine_size_category(self, pet_type: str, weight: float) -> str:
    """
    确定宠物体型分类
    
    Args:
        pet_type: 宠物类型
        weight: 体重
        
    Returns:
        体型分类
    """
    type_config = PET_TYPES.get(pet_type, {})
    
    for category, info in type_config.items():
        weight_range = in

关注我,有更多实用程序等着你!