Polars实战:用泰坦尼克号数据集手把手教你高效数据分析(附完整代码)
Polars实战:用泰坦尼克号数据集手把手教你高效数据分析(附完整代码)
数据分析领域正在经历一场效率革命。传统工具如Pandas在处理大规模数据时逐渐显露出性能瓶颈,而新一代的Polars凭借其Rust语言底层和并行计算架构,正在成为数据科学家和工程师的新宠。本文将带你通过经典的泰坦尼克号数据集,从零开始掌握Polars的核心操作技巧,体验比传统方法快5-10倍的数据处理速度。
1. 环境准备与数据加载
在开始之前,确保你已经安装了最新版本的Polars。建议使用Python 3.8及以上版本,并通过以下命令安装:
pip install polars泰坦尼克号数据集是机器学习入门的经典案例,包含了乘客的舱位等级、姓名、性别、年龄、票价以及是否生还等信息。我们可以直接从网络获取这个数据集:
import polars as pl # 设置显示选项 pl.Config.set_tbl_rows(10) # 显示10行数据 pl.Config.set_fmt_str_lengths(50) # 字符串显示长度 # 直接从URL加载数据 url = "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv" df = pl.read_csv(url)初次接触数据时,快速了解数据结构至关重要。Polars提供了几种直观的查看方式:
# 查看前几行 print(df.head()) # 查看数据结构 print(df.schema) # 统计概览 print(df.describe())提示:与Pandas不同,Polars的
describe()输出会自动包含null值统计,这对数据质量检查非常有用。
2. 数据清洗与预处理
真实世界的数据往往不够完美。让我们先处理缺失值和异常数据:
# 检查各列缺失值 null_counts = df.null_count() print(null_counts) # 年龄列处理:用中位数填充缺失值 median_age = df["Age"].median() df = df.with_columns( pl.col("Age").fill_null(median_age).alias("Age") ) # 票价异常值处理:移除为0的票价 df = df.filter(pl.col("Fare") > 0)数据类型转换也是预处理的重要环节:
# 转换数据类型 df = df.with_columns( pl.col("Survived").cast(pl.Boolean), pl.col("Pclass").cast(pl.UInt8) )对于分类变量,我们可以创建虚拟变量(dummy variables):
# 为Embarked列创建虚拟变量 df = df.with_columns( pl.col("Embarked").str.to_uppercase().alias("Embarked") ) df = df.to_dummies(columns=["Embarked", "Sex"])3. 高效数据操作:表达式API实战
Polars的核心优势在于其表达式API,它允许我们以声明式的方式编写复杂的数据转换。让我们通过几个实际案例来掌握这一强大工具。
3.1 基本列操作
# 选择特定列 selected = df.select(["Name", "Age", "Fare"]) print(selected.head()) # 添加计算列 df = df.with_columns( (pl.col("Fare") / pl.col("Age")).alias("FarePerYear") ) # 条件赋值 df = df.with_columns( pl.when(pl.col("Age") < 18) .then("Child") .otherwise("Adult") .alias("AgeGroup") )3.2 字符串处理
Polars提供了丰富的字符串操作方法:
# 提取姓名中的称谓 df = df.with_columns( pl.col("Name").str.extract(r" ([A-Za-z]+)\.", 1).alias("Title") ) # 常见称谓标准化 title_mapping = { "Mlle": "Miss", "Ms": "Miss", "Mme": "Mrs" } df = df.with_columns( pl.col("Title").replace(title_mapping).alias("Title") )3.3 高级表达式组合
表达式可以链式组合,实现复杂转换:
# 多条件复杂表达式 df = df.with_columns( pl.col("Fare") .log() .clip(lower_bound=0, upper_bound=5) .alias("NormalizedFare") ) # 多列交互计算 df = df.with_columns( (pl.col("Age") * pl.col("Pclass")).alias("AgeClassScore") )4. 数据分析与聚合
有了干净的数据,我们可以开始深入分析。Polars的聚合操作特别适合处理大规模数据。
4.1 基本统计分析
# 按舱位统计生存率 survival_by_class = df.group_by("Pclass").agg( pl.col("Survived").mean().alias("SurvivalRate"), pl.count().alias("PassengerCount") ) print(survival_by_class)4.2 多维度交叉分析
# 按性别和舱位分析生存率 survival_analysis = df.group_by(["Sex_male", "Pclass"]).agg( pl.col("Survived").mean().alias("SurvivalRate"), pl.col("Age").mean().alias("MeanAge"), pl.col("Fare").mean().alias("MeanFare") ) print(survival_analysis.sort("SurvivalRate", descending=True))4.3 窗口函数应用
窗口函数允许我们在不实际分组的情况下计算分组统计量:
# 计算每个舱位的年龄排名 df = df.with_columns( pl.col("Age").rank(method="average").over("Pclass").alias("AgeRankInClass") ) # 计算移动平均 df = df.sort("Age").with_columns( pl.col("Fare").rolling_mean(window_size=5).alias("FareRollingMean") )5. 性能优化技巧
Polars的真正威力在于其性能。下面介绍几种最大化利用其能力的方法。
5.1 惰性执行模式
惰性模式允许Polars优化整个查询计划:
# 惰性模式示例 lazy_df = ( pl.scan_csv(url) .filter(pl.col("Age") > 18) .group_by(["Pclass", "Sex_male"]) .agg( pl.col("Survived").mean().alias("SurvivalRate"), pl.col("Fare").mean().alias("MeanFare") ) ) # 查看优化后的查询计划 print(lazy_df.explain()) # 执行查询 results = lazy_df.collect() print(results)5.2 并行处理配置
Polars默认使用所有CPU核心,但我们可以精细控制:
# 设置并行线程数 pl.Config.set_global_string_cache(True) # 对分类变量优化 pl.Config.set_tbl_cols(20) # 显示更多列 # 强制使用特定数量的线程 import os os.environ["POLARS_MAX_THREADS"] = "4"5.3 内存管理技巧
处理大数据时,内存效率至关重要:
# 使用更高效的数据类型 df = df.with_columns( pl.col("Pclass").cast(pl.UInt8), pl.col("Age").cast(pl.Float32) ) # 流式处理大数据 large_result = ( pl.scan_csv(url) .filter(pl.col("Age") > 30) .group_by("Pclass") .agg(pl.count().alias("Count")) .collect(streaming=True) )6. 可视化集成
虽然Polars本身不提供可视化功能,但它可以无缝集成主流可视化库。
6.1 与Matplotlib集成
import matplotlib.pyplot as plt # 准备数据 class_survival = df.group_by("Pclass").agg( pl.col("Survived").mean().alias("SurvivalRate") ).sort("Pclass") # 绘制柱状图 plt.bar( class_survival["Pclass"].to_list(), class_survival["SurvivalRate"].to_list() ) plt.xlabel("Passenger Class") plt.ylabel("Survival Rate") plt.title("Survival Rate by Passenger Class") plt.show()6.2 与Plotly交互式可视化
import plotly.express as px # 创建交互式散点图 fig = px.scatter( df.to_pandas(), # Plotly目前对Polars原生支持有限 x="Age", y="Fare", color="Survived", hover_data=["Name", "Pclass"] ) fig.show()7. 完整案例分析:预测生存因素
让我们综合运用所学知识,分析哪些因素最影响生存率。
# 计算各特征与生存率的相关系数 correlation_analysis = df.select([ pl.corr("Survived", "Age").alias("AgeCorr"), pl.corr("Survived", "Fare").alias("FareCorr"), pl.corr("Survived", "Pclass").alias("ClassCorr"), pl.corr("Survived", "Sex_male").alias("SexCorr") ]) print(correlation_analysis) # 多因素分析 significant_factors = ( df.group_by(["Pclass", "AgeGroup", "Sex_male"]) .agg( pl.col("Survived").mean().alias("SurvivalRate"), pl.count().alias("Count") ) .sort("SurvivalRate", descending=True) ) print(significant_factors)从分析结果可以看出,性别、舱位等级和年龄是影响生存率的最显著因素。一等舱的女性乘客生存率最高,而三等舱的男性成年乘客生存率最低。
8. 进阶技巧与最佳实践
在项目中使用Polars时,这些技巧能帮你避免常见陷阱:
- 避免混用Pandas:频繁转换会抵消性能优势,尽量全程使用Polars
- 合理使用惰性模式:对于复杂多步操作,惰性模式能显著提升性能
- 注意字符串处理:Polars的字符串操作与Python略有不同,需要适应
- 利用并行优势:确保操作是可并行的,避免顺序依赖
# 性能对比示例 import time # Polars处理 start = time.time() polars_result = df.group_by("Pclass").agg(pl.count()).collect() print(f"Polars耗时: {time.time()-start:.4f}秒") # Pandas处理(对比) import pandas as pd pdf = pd.read_csv(url) start = time.time() pandas_result = pdf.groupby("Pclass").size() print(f"Pandas耗时: {time.time()-start:.4f}秒")在我的测试环境中,Polars的处理速度通常比Pandas快3-5倍,对于更复杂的操作,优势可能达到10倍以上。
