百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Python高效数据处理——从基础方法到性能优化

itomcoil 2025-07-24 18:47 5 浏览

数据处理是数据分析的核心环节,高效的数据处理方法能显著提升代码性能。本文将深入介绍Pandas中的各种数据处理技术,并分析它们的性能特点。

使用apply方法应用自定义函数

apply是Pandas中最灵活的数据处理方法之一,可以对Series或DataFrame的行/列应用自定义函数。

Series的apply方法

import pandas as pd
import numpy as np

# 创建示例Series
s = pd.Series([1, 2, 3, 4, 5])

# 使用apply应用平方函数
squared = s.apply(lambda x: x**2)
print("平方后的Series:")
print(squared)

# 使用命名函数
def add_prefix(x):
    return f"值_{x}"

prefixed = s.apply(add_prefix)
print("\n添加前缀后的Series:")
print(prefixed)

DataFrame的apply方法

# 创建示例DataFrame
df = pd.DataFrame({
    'A': np.random.randint(1, 10, 5),
    'B': np.random.randn(5),
    'C': np.random.choice(['X', 'Y', 'Z'], 5)
})

# 对列应用函数
col_sum = df.apply(np.sum, axis=0)  # axis=0对列操作
print("\n列求和结果:")
print(col_sum)

# 对行应用函数
row_max = df.apply(np.max, axis=1)  # axis=1对行操作
print("\n行最大值结果:")
print(row_max)

# 复杂行处理
def process_row(row):
    return f"{row['C']}_{round(row['A'] * row['B'], 2)}"

processed = df.apply(process_row, axis=1)
print("\n复杂行处理结果:")
print(processed)

性能考虑

# 创建大数据集测试性能
big_df = pd.DataFrame(np.random.randn(10000, 4), columns=['A', 'B', 'C', 'D'])

# 测试apply性能
%timeit big_df.apply(np.sum, axis=0)  # 列操作通常较快
%timeit big_df.apply(np.sum, axis=1)  # 行操作较慢

使用map和applymap方法

map方法(Series专用)

# 创建示例Series
s = pd.Series(['cat', 'dog', 'cat', 'bird'])

# 简单映射
simple_map = s.map({'cat': '猫', 'dog': '狗', 'bird': '鸟'})
print("\n简单映射结果:")
print(simple_map)

# 函数映射
length_map = s.map(lambda x: len(x))
print("\n字符串长度映射:")
print(length_map)

# 使用str方法替代简单映射
print("\nstr方法实现:")
print(s.str.len())

applymap方法(DataFrame专用)

# 创建示例DataFrame
df = pd.DataFrame(np.random.randn(3, 3), columns=['A', 'B', 'C'])

# 对所有元素应用函数
rounded = df.applymap(lambda x: round(x, 2))
print("\n四舍五入后的DataFrame:")
print(rounded)

# 条件应用
def format_cell(x):
    if x > 0:
        return f"+{x:.2f}"
    return f"{x:.2f}"

formatted = df.applymap(format_cell)
print("\n格式化后的DataFrame:")
print(formatted)

性能对比

# 比较applymap与向量化操作
%timeit df.applymap(lambda x: x * 2)
%timeit df * 2  # 向量化操作快得多

使用iterrows和itertuples进行迭代

虽然Pandas通常推荐向量化操作,但有时迭代是必要的。

iterrows方法

# 创建示例DataFrame
df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'age': [25, 30, 35],
    'score': [85, 92, 78]
})

# 使用iterrows迭代
print("\n使用iterrows迭代:")
for index, row in df.iterrows():
    print(f"索引: {index}, 姓名: {row['name']}, 年龄+分数: {row['age'] + row['score']}")

itertuples方法(更快)

# 使用itertuples迭代
print("\n使用itertuples迭代:")
for row in df.itertuples():
    print(f"索引: {row.Index}, 姓名: {row.name}, 年龄+分数: {row.age + row.score}")

性能对比

# 创建大数据集
big_df = pd.DataFrame(np.random.randn(10000, 4), columns=['A', 'B', 'C', 'D'])

# 比较各种迭代方法
%timeit for index, row in big_df.iterrows(): pass  # 最慢
%timeit for row in big_df.itertuples(): pass  # 较快
%timeit for col in big_df.items(): pass  # 列迭代

使用vectorize加速数值计算

NumPy的vectorize函数可以将Python函数转换为向量化函数,提高性能。

基础vectorize使用

import numpy as np

# 定义普通Python函数
def my_func(x):
    if x > 0:
        return x ** 2
    else:
        return x / 2

# 创建数组
arr = np.array([1, -2, 3, -4, 5])

# 普通Python循环
result = [my_func(x) for x in arr]
print("普通循环结果:", result)

# 使用vectorize
vec_func = np.vectorize(my_func)
vec_result = vec_func(arr)
print("\nvectorize结果:", vec_result)

性能对比

# 创建大型数组
big_arr = np.random.randn(1000000)

# 性能测试
%timeit [my_func(x) for x in big_arr]  # Python循环
%timeit np.vectorize(my_func)(big_arr)  # vectorize
%timeit np.where(big_arr > 0, big_arr**2, big_arr/2)  # 纯NumPy向量化

结合Pandas使用

# 在Pandas中使用vectorize
df = pd.DataFrame(np.random.randn(1000, 3), columns=['A', 'B', 'C'])

# 定义复杂函数
def complex_calc(a, b, c):
    return a**2 + b*3 + np.sqrt(abs(c))

# 普通apply方法
%timeit df.apply(lambda row: complex_calc(row['A'], row['B'], row['C']), axis=1)

# 使用vectorize
vec_complex = np.vectorize(complex_calc)
%timeit vec_complex(df['A'], df['B'], df['C'])

实战案例:电商数据分析

# 创建模拟电商数据集
np.random.seed(42)
n = 100000
data = {
    'order_id': range(1000, 1000 + n),
    'user_id': np.random.randint(100, 200, n),
    'product_id': np.random.choice(['A100', 'B200', 'C300', 'D400'], n),
    'price': np.random.uniform(10, 500, n).round(2),
    'quantity': np.random.randint(1, 10, n),
    'is_member': np.random.choice([True, False], n)
}
ecom_df = pd.DataFrame(data)

# 计算总金额
# 方法1: 简单列运算 (最快)
ecom_df['total'] = ecom_df['price'] * ecom_df['quantity']

# 方法2: 使用apply (较慢但灵活)
def calc_total(row):
    discount = 0.9 if row['is_member'] else 1.0
    return row['price'] * row['quantity'] * discount

ecom_df['total_with_discount'] = ecom_df.apply(calc_total, axis=1)

# 方法3: 使用vectorize (折中方案)
@np.vectorize
def vec_calc_total(price, quantity, is_member):
    discount = 0.9 if is_member else 1.0
    return price * quantity * discount

ecom_df['total_vec'] = vec_calc_total(
    ecom_df['price'], 
    ecom_df['quantity'], 
    ecom_df['is_member']
)

# 性能比较
print("\n性能比较:")
%timeit ecom_df['price'] * ecom_df['quantity']
%timeit ecom_df.apply(calc_total, axis=1)
%timeit vec_calc_total(ecom_df['price'], ecom_df['quantity'], ecom_df['is_member'])

最佳实践与性能优化

方法选择指南

场景

推荐方法

备注

简单列运算

直接向量化运算

df['A'] + df['B']

复杂行处理

apply(axis=1)

灵活性高但性能较低

元素级转换

applymap或map

DataFrame或Series专用

高性能迭代

itertuples

比iterrows快得多

数值计算加速

np.vectorize

介于纯Python和纯NumPy之间

性能优化技巧

# 1. 避免链式操作
# 不推荐
result = df[df['A'] > 0]['B']
# 推荐
result = df.loc[df['A'] > 0, 'B']

# 2. 使用eval实现高效列运算
expr = "(A + B) / (C - D)"
result = df.eval(expr)

# 3. 使用category类型减少内存
df['category_col'] = df['category_col'].astype('category')

常见陷阱与解决方案

# 陷阱1: apply中的意外副作用
def bad_func(row):
    print(row)  # 副作用:打印
    return row['A'] + row['B']
# 解决方案:确保函数是纯函数

# 陷阱2: 修改迭代中的行无效
for index, row in df.iterrows():
    row['A'] = 0  # 不会修改原DataFrame
# 解决方案:使用.loc直接修改
for index, _ in df.iterrows():
    df.loc[index, 'A'] = 0

总结与进阶学习

核心要点总结

  • apply:灵活但性能不高,适合复杂行/列操作
  • map/applymap:元素级转换的专用方法
  • 迭代方法:itertuples > iterrows,但都应作为最后选择
  • vectorize:加速Python函数的好方法,但仍不如纯NumPy操作

进阶学习方向

# 1. 使用Numba加速Python函数
# from numba import vectorize
# @vectorize
# def numba_func(x): ...

# 2. 使用Dask处理超大数据集
# import dask.dataframe as dd
# ddf = dd.from_pandas(df, npartitions=4)

# 3. 使用Cython编写高性能扩展
# %load_ext Cython
# %%cython
# def cython_func(): ...

掌握这些高效数据处理技巧后,我们就可以处理各种规模的数据分析任务了。记住,在Pandas中,向量化操作通常是最佳选择,只有在必要时才使用迭代方法。

相关推荐

Python高效数据处理——从基础方法到性能优化

数据处理是数据分析的核心环节,高效的数据处理方法能显著提升代码性能。本文将深入介绍Pandas中的各种数据处理技术,并分析它们的性能特点。使用apply方法应用自定义函数apply是Pandas中最灵...

正态分布-置信区间计算(正态90%置信区间)

统计学有两大主要分支,分别是描述性统计学和推断统计学。描述性统计学用于描述和概括数据的特征以及绘制各类统计图表。总体数据,往往因为数据量太大而难以被获取,所以就有了通过较小的样本数据推测总体特性的推断...

一篇文章搞定人工智能之深度学习创建训练数据集的方法

基础数据准备训练所需要的数据集合都存储在数据库中,还有部分文本文件首先对数据进行分类结构化存储[因为涉及到的是多分类问题]整理并存储原始数据集使用numpy将所有需要数据读取出来splitlines(...

向量搜索之 k-means 算法(annoy向量检索)

一直好奇向量数据库的索引是如何实现的,我们可以推断向量搜索的简单实现:把数据存入向量数据库时,会计算每个分段文档的向量(文档向量),然后把分段文档和文档向量同时存入向量数据库。从向量数据库中搜索文档时...

融合贝叶斯生存模型与Transformer注意力的客户重参与策略优化

本文提出了一个集成三种核心技术的下一代智能优惠券分发系统:基于贝叶斯生存模型的重购概率预测、采用注意力机制的Transformer利润预测模型,以及用于策略持续优化的Dyna-Q强化学习代理。该系统构...

用Deepseek编写代码计算今天大乐透开奖号码

以下是一个基于Python的示例代码,用于分析大乐透历史数据并生成可能的号码组合。请务必注意:这仅是统计学模拟,无法真正预测开奖结果,所有结果均为随机性参考。代码实现步骤1.数据准备(模拟数据)假设...

拆解特斯拉L2家用充电桩:技术细节太多了

本文是对第三代特斯拉家用充电桩(L2级)的拆解分析报告。深入探究该充电桩的内部结构、设计特点、性能参数等内容。产品概述设备为第三代特斯拉家用充电桩,属于Level2充电器,是特斯拉推出的家用充电设备...

《光环5》2月更新“战锤风暴”正式推送“枪林弹雨”模式即将到来

今天(2月25日)微软和343工作室正式向Xboxone玩家推送了《光环5》的2月更新补丁“战锤风暴HammerStorm”。本次更新包括了1张全新Arena竞技场地图Torque;3个全新游戏模式...

Spring Boot(十一)Redis集成从Docker安装到分布式Session共享

一、简介Redis是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API,Redis也是技术领域使用最为广泛的存储中间件,它是「...

Mac 基于HTTP方式访问下载共享文件,配置共享服务器

方法一:使用Python的SimpleHTTPServer进行局域网文件共享Mac自带Python,所以不需要安装其他软件,一条命令即可1):进入需要共享的文件夹,如Public文件夹cd/Us...

移动端性能专项测试之 CPU(移动端cpu天梯图2020百度贴吧)

指标背景很多场景下我们去使用App,可能会碰到手机会出现发热发烫的现象。这是因为CPU使用率过高、CPU过于繁忙,会使得整个系统无法响应用户,整体性能降低,用户体验变得相当差,也容易引起AN...

如何三天学会Phyton?这篇文章教你快速编程入门

Phyton作为一门常用的语言在很多领域都有很应用,很多人都想学习这门语言,那么我们就开始从头学习这门语言吧!首先你需要在官网下载你的Phyton的编程工具,也就是下载你的解释器!登录Phyton官网...

学习Python第一天 ---Hello World

引言人生苦短,请用Python(3.+)越来越多的情况下使用Python语言进行"代码粘合"和"数据分析"变得非常方便,而且Python在"爬虫"...

mysql的MVCC多版本并发控制机制(mysql并发情况下怎么解决)

认识MVCCMVCC是英文Multi-VersionConcurrencyControl多版本并发控制的首字母简拼。在上文MYSQL事务隔离级别中,我们已经知道,在可重复读的级别下,不管其他事...

爆炸,MySQL9.0大版本发布,我严重怀疑,它是不...

MySQL在本月发布了9.0大版本,作为MySQL的忠实粉丝,简单说下这次大版本更新。1.企业版,支持JS存储程序(JavaScriptstoredprograms)了。例如,可以像这样定一个函...