【AI Study】第四天,Pandas(8)- 最佳实践

文章概要

本文详细介绍 Pandas 的最佳实践,包括:

  • 代码规范
  • 性能调优
  • 错误处理
  • 实际应用示例

代码规范

命名规范

# 变量命名
# 推荐
df_sales = pd.DataFrame()  # 使用 df_ 前缀表示 DataFrame
s_prices = pd.Series()     # 使用 s_ 前缀表示 Series
idx_dates = pd.date_range()  # 使用 idx_ 前缀表示索引

# 不推荐
data = pd.DataFrame()      # 过于笼统
p = pd.Series()           # 过于简短
dates = pd.date_range()   # 不够明确

# 函数命名
# 推荐
def calculate_mean_sales(df):
    return df['sales'].mean()

def process_customer_data(df):
    return df.groupby('customer_id').agg({
        'purchase_amount': 'sum',
        'visit_count': 'count'
    })

# 不推荐
def mean(df):             # 过于简短
def process(df):          # 过于笼统
def do_something(df):     # 不够具体

代码结构

# 导入规范
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 常量定义
MAX_ROWS = 1000
DEFAULT_CHUNK_SIZE = 10000
DATE_FORMAT = '%Y-%m-%d'

# 工具函数
def load_data(file_path):
    """加载数据文件
    
    Args:
        file_path (str): 数据文件路径
        
    Returns:
        pd.DataFrame: 加载的数据
    """
    return pd.read_csv(file_path)

def process_data(df):
    """处理数据
    
    Args:
        df (pd.DataFrame): 输入数据
        
    Returns:
        pd.DataFrame: 处理后的数据
    """
    # 数据清洗
    df = clean_data(df)
    
    # 特征工程
    df = engineer_features(df)
    
    # 数据验证
    validate_data(df)
    
    return df

# 主函数
def main():
    # 加载数据
    df = load_data('data.csv')
    
    # 处理数据
    df_processed = process_data(df)
    
    # 保存结果
    df_processed.to_csv('processed_data.csv', index=False)

if __name__ == '__main__':
    main()

注释规范

def analyze_sales_data(df, group_by='product', metrics=None):
    """分析销售数据
    
    该函数用于分析销售数据,计算各种统计指标。
    
    Args:
        df (pd.DataFrame): 销售数据
        group_by (str, optional): 分组字段. 默认为 'product'.
        metrics (list, optional): 需要计算的指标列表. 默认为 None.
    
    Returns:
        pd.DataFrame: 分析结果
        
    Raises:
        ValueError: 当输入数据为空时抛出
        KeyError: 当指定的列不存在时抛出
        
    Examples:
        >>> df = pd.DataFrame({'product': ['A', 'B'], 'sales': [100, 200]})
        >>> result = analyze_sales_data(df)
        >>> print(result)
    """
    # 参数验证
    if df.empty:
        raise ValueError("输入数据不能为空")
    
    if group_by not in df.columns:
        raise KeyError(f"列 {group_by} 不存在")
    
    # 设置默认指标
    if metrics is None:
        metrics = ['sum', 'mean', 'count']
    
    # 计算统计指标
    result = df.groupby(group_by).agg({
        'sales': metrics,
        'quantity': metrics
    })
    
    return result

性能调优

代码优化

# 避免循环
# 不推荐
def calculate_total_sales(df):
    total = 0
    for i in range(len(df)):
        total += df.iloc[i]['price'] * df.iloc[i]['quantity']
    return total

# 推荐
def calculate_total_sales(df):
    return (df['price'] * df['quantity']).sum()

# 使用向量化操作
# 不推荐
def calculate_discount(df):
    for i in range(len(df)):
        if df.iloc[i]['price'] > 100:
            df.iloc[i]['discount'] = 0.1
        else:
            df.iloc[i]['discount'] = 0.05

# 推荐
def calculate_discount(df):
    df['discount'] = np.where(df['price'] > 100, 0.1, 0.05)

# 使用 apply 而不是循环
# 不推荐
def process_categories(df):
    for i in range(len(df)):
        df.iloc[i]['category'] = process_category(df.iloc[i]['name'])

# 推荐
def process_categories(df):
    df['category'] = df['name'].apply(process_category)

内存管理

# 优化数据类型
def optimize_dtypes(df):
    """优化 DataFrame 的数据类型以减少内存使用
    
    Args:
        df (pd.DataFrame): 输入数据
        
    Returns:
        pd.DataFrame: 优化后的数据
    """
    # 优化数值类型
    for col in df.select_dtypes(include=['int']).columns:
        df[col] = pd.to_numeric(df[col], downcast='integer')
    
    for col in df.select_dtypes(include=['float']).columns:
        df[col] = pd.to_numeric(df[col], downcast='float')
    
    # 优化分类数据
    for col in df.select_dtypes(include=['object']).columns:
        if df[col].nunique() / len(df) < 0.5:  # 如果唯一值比例小于50%
            df[col] = df[col].astype('category')
    
    return df

# 清理内存
def clean_memory():
    """清理内存"""
    import gc
    gc.collect()

# 使用示例
df = pd.DataFrame({
    'id': range(1000000),
    'value': np.random.randn(1000000),
    'category': np.random.choice(['A', 'B', 'C'], 1000000)
})

# 优化数据类型
df = optimize_dtypes(df)

# 清理内存
clean_memory()

执行效率

# 使用适当的数据结构
# 不推荐
def find_duplicates(df):
    duplicates = []
    for i in range(len(df)):
        for j in range(i+1, len(df)):
            if df.iloc[i].equals(df.iloc[j]):
                duplicates.append(i)
    return duplicates

# 推荐
def find_duplicates(df):
    return df[df.duplicated()].index.tolist()

# 使用索引
# 不推荐
def filter_by_date(df, date):
    return df[df['date'] == date]

# 推荐
def filter_by_date(df, date):
    df = df.set_index('date')
    return df.loc[date]

# 使用分块处理
def process_large_file(file_path, chunk_size=10000):
    """分块处理大文件
    
    Args:
        file_path (str): 文件路径
        chunk_size (int): 块大小
        
    Returns:
        pd.DataFrame: 处理结果
    """
    results = []
    for chunk in pd.read_csv(file_path, chunksize=chunk_size):
        # 处理每个数据块
        processed_chunk = process_chunk(chunk)
        results.append(processed_chunk)
    
    return pd.concat(results)

错误处理

异常处理

# 基本异常处理
def safe_read_csv(file_path):
    """安全读取 CSV 文件
    
    Args:
        file_path (str): 文件路径
        
    Returns:
        pd.DataFrame: 读取的数据
        
    Raises:
        FileNotFoundError: 文件不存在时抛出
        pd.errors.EmptyDataError: 文件为空时抛出
    """
    try:
        df = pd.read_csv(file_path)
        if df.empty:
            raise pd.errors.EmptyDataError("文件为空")
        return df
    except FileNotFoundError:
        print(f"文件 {file_path} 不存在")
        raise
    except pd.errors.EmptyDataError:
        print(f"文件 {file_path} 为空")
        raise
    except Exception as e:
        print(f"读取文件时发生错误: {str(e)}")
        raise

# 自定义异常
class DataValidationError(Exception):
    """数据验证错误"""
    pass

def validate_data(df):
    """验证数据
    
    Args:
        df (pd.DataFrame): 输入数据
        
    Raises:
        DataValidationError: 数据验证失败时抛出
    """
    # 检查必需列
    required_columns = ['id', 'name', 'value']
    missing_columns = [col for col in required_columns if col not in df.columns]
    if missing_columns:
        raise DataValidationError(f"缺少必需列: {missing_columns}")
    
    # 检查数据类型
    if not pd.api.types.is_numeric_dtype(df['value']):
        raise DataValidationError("'value' 列必须是数值类型")
    
    # 检查空值
    if df['id'].isnull().any():
        raise DataValidationError("'id' 列不能包含空值")

数据验证

# 数据验证函数
def validate_numeric_range(df, column, min_value=None, max_value=None):
    """验证数值范围
    
    Args:
        df (pd.DataFrame): 输入数据
        column (str): 列名
        min_value (float, optional): 最小值
        max_value (float, optional): 最大值
        
    Returns:
        bool: 验证是否通过
    """
    if min_value is not None:
        if (df[column] < min_value).any():
            return False
    
    if max_value is not None:
        if (df[column] > max_value).any():
            return False
    
    return True

def validate_categorical_values(df, column, allowed_values):
    """验证分类值
    
    Args:
        df (pd.DataFrame): 输入数据
        column (str): 列名
        allowed_values (list): 允许的值列表
        
    Returns:
        bool: 验证是否通过
    """
    return df[column].isin(allowed_values).all()

# 使用示例
df = pd.DataFrame({
    'age': [20, 30, 40, 50],
    'category': ['A', 'B', 'C', 'D']
})

# 验证年龄范围
is_valid_age = validate_numeric_range(df, 'age', min_value=0, max_value=100)

# 验证分类值
is_valid_category = validate_categorical_values(df, 'category', ['A', 'B', 'C'])

日志记录

# 日志记录
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    filename='pandas_analysis.log'
)

def process_data_with_logging(df):
    """带日志记录的数据处理
    
    Args:
        df (pd.DataFrame): 输入数据
    """
    logger = logging.getLogger(__name__)
    
    try:
        # 记录开始处理
        logger.info(f"开始处理数据,形状: {df.shape}")
        
        # 数据清洗
        df = clean_data(df)
        logger.info("数据清洗完成")
        
        # 特征工程
        df = engineer_features(df)
        logger.info("特征工程完成")
        
        # 数据验证
        validate_data(df)
        logger.info("数据验证通过")
        
        return df
        
    except Exception as e:
        logger.error(f"处理数据时发生错误: {str(e)}")
        raise

总结

最佳实践部分涵盖了:

  1. 代码规范(命名规范、代码结构、注释规范)
  2. 性能调优(代码优化、内存管理、执行效率)
  3. 错误处理(异常处理、数据验证、日志记录)
  4. 实际应用示例

掌握这些最佳实践对于开发高质量的 Pandas 代码至关重要,它可以帮助我们:

  • 提高代码可读性
  • 提升代码性能
  • 增强代码可靠性
  • 便于维护和协作

建议在实际项目中注意:

  • 遵循代码规范
  • 注重性能优化
  • 做好错误处理
  • 保持代码简洁
  • 编写清晰注释
  • 进行代码审查
  • 持续改进代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值