Pandas
问题
Pandas 的 DataFrame 核心操作有哪些?如何处理大数据量?
答案
核心数据结构
import pandas as pd
# Series:一维带标签数组
s = pd.Series([1, 2, 3], index=["a", "b", "c"])
# DataFrame:二维带标签表格
df = pd.DataFrame({
"name": ["Alice", "Bob", "Charlie"],
"age": [25, 30, 35],
"salary": [50000, 60000, 70000],
})
数据读写
# CSV
df = pd.read_csv("data.csv", dtype={"id": str}, parse_dates=["created_at"])
df.to_csv("output.csv", index=False)
# Parquet(推荐大文件)
df = pd.read_parquet("data.parquet")
df.to_parquet("output.parquet")
# SQL
df = pd.read_sql("SELECT * FROM users", engine)
分组聚合
# groupby + 聚合
result = df.groupby("department").agg(
avg_salary=("salary", "mean"),
count=("name", "count"),
max_salary=("salary", "max"),
).reset_index()
# 自定义聚合
df.groupby("department")["salary"].apply(lambda x: x.quantile(0.9))
# 透视表
pivot = df.pivot_table(
values="salary",
index="department",
columns="level",
aggfunc="mean",
)
数据清洗
# 缺失值处理
df.dropna(subset=["email"]) # 删除空行
df["age"].fillna(df["age"].median()) # 中位数填充
df["name"].isna().sum() # 统计缺失数
# 类型转换
df["date"] = pd.to_datetime(df["date"])
df["price"] = df["price"].astype(float)
# 去重
df.drop_duplicates(subset=["email"], keep="first")
# 字符串操作
df["name"] = df["name"].str.strip().str.lower()
性能优化
# 1. 减少内存:指定 dtype
df = pd.read_csv("data.csv", dtype={"id": "int32", "flag": "category"})
# 2. 按块读取大文件
for chunk in pd.read_csv("big.csv", chunksize=10000):
process(chunk)
# 3. 使用 Parquet 代替 CSV(压缩 + 列式存储)
df.to_parquet("data.parquet", compression="snappy")
# 4. 向量化操作代替 apply
df["new"] = df["a"] + df["b"] # ✅ 比 apply 快 100x
常见面试问题
Q1: Pandas 和 Polars 的区别?
答案:
| 特性 | Pandas | Polars |
|---|---|---|
| 语言 | C/Cython | Rust |
| 并行 | 单线程 | 多线程 |
| 惰性求值 | 无 | LazyFrame |
| 内存模型 | 行索引 | Apache Arrow 列式 |
| 速度 | 基准 | 快 5-30x |
| 生态 | 极丰富 | 快速增长 |
Q2: apply 为什么慢?
答案:
apply 会对每一行调用 Python 函数,经过 Python 解释器。向量化操作直接调用 C 扩展。优先用内置方法(str., dt., 算术运算)代替 apply。
Q3: merge 和 join 的区别?
答案:
# merge:基于列合并(类似 SQL JOIN)
result = pd.merge(df1, df2, on="user_id", how="left")
# join:基于索引合并
result = df1.join(df2, how="inner")
# concat:纵向/横向拼接
result = pd.concat([df1, df2], axis=0) # 纵向拼接
Q4: 如何处理时间序列?
答案:
df["date"] = pd.to_datetime(df["date"])
df.set_index("date", inplace=True)
# 重采样
monthly = df.resample("M").mean() # 月平均
weekly = df.resample("W").sum() # 周求和
# 滚动窗口
df["ma7"] = df["price"].rolling(7).mean() # 7 日均线