Pandas 高级技巧与最佳实践目标掌握 Pandas 的进阶用法和性能优化技巧成为 Pandas 高手。11.1 性能优化11.1.1 向量化 vs 循环importpandasaspdimportnumpyasnpimporttime# 创建大数据集n1_000_000dfpd.DataFrame({A:np.random.randn(n),B:np.random.randn(n)})# ❌ 慢用循环defloop_add(df):result[]foriinrange(len(df)):result.append(df.iloc[i][A]df.iloc[i][B])returnresult starttime.time()loop_resultloop_add(df)print(f循环耗时:{time.time()-start:.2f}秒)# ✅ 快用向量化starttime.time()vector_resultdf[A]df[B]print(f向量化耗时:{time.time()-start:.4f}秒)黄金法则永远不要对 DataFrame 用循环11.1.2 使用合适的数据类型# 创建示例数据dfpd.DataFrame({int64_col:np.random.randint(0,100,1000000),float64_col:np.random.randn(1000000),category_col:np.random.choice([A,B,C,D],1000000),object_col:np.random.choice([北京,上海,广州,深圳],1000000)})print(原始内存使用:)print(df.memory_usage(deepTrue).sum()/1024**2,MB)# 优化数据类型df_optimizeddf.copy()df_optimized[int64_col]df_optimized[int64_col].astype(int32)# int64 → int32df_optimized[float64_col]df_optimized[float64_col].astype(float32)# float64 → float32df_optimized[category_col]df_optimized[category_col].astype(category)df_optimized[object_col]df_optimized[object_col].astype(category)print(\n优化后内存使用:)print(df_optimized.memory_usage(deepTrue).sum()/1024**2,MB)11.1.3 使用 eval 和 query# 创建大数据dfpd.DataFrame(np.random.randn(100000,4),columns[A,B,C,D])# eval高效计算# 普通方式df[E]df[A]df[B]*df[C]-df[D]# eval 方式更快df[E]df.eval(A B * C - D)# query高效筛选# 普通方式resultdf[(df[A]0)(df[B]0)]# query 方式更快resultdf.query(A 0 and B 0)11.2 内存优化11.2.1 分块读取大文件# 分块读取 CSVchunk_size100000chunks[]forchunkinpd.read_csv(large_file.csv,chunksizechunk_size):# 处理每个 chunkprocessedchunk[chunk[value]0]# 示例处理chunks.append(processed)# 合并结果dfpd.concat(chunks,ignore_indexTrue)11.2.2 使用迭代器# 迭代器方式读取forchunkinpd.read_csv(large_file.csv,chunksize10000):forrowinchunk.itertuples():# 处理每一行pass11.2.3 删除中间变量# ❌ 内存占用大df1pd.read_csv(data.csv)df2df1[df1[A]0]df3df2.groupby(B).sum()df4df3.reset_index()# ✅ 及时释放内存dfpd.read_csv(data.csv)dfdf[df[A]0]dfdf.groupby(B).sum()dfdf.reset_index()11.3 链式操作11.3.1 方法链式调用# ❌ 传统方式多个变量dfpd.read_csv(data.csv)dfdf[df[A]0]dfdf.dropna()dfdf.assign(Clambdax:x[A]x[B])dfdf.groupby(D).sum()# ✅ 链式操作一个表达式result(pd.read_csv(data.csv).query(A 0).dropna().assign(Clambdax:x[A]x[B]).groupby(D).sum().reset_index())11.3.2 使用 pipe# 自定义函数deffilter_positive(df,col):returndf[df[col]0]defadd_ratio(df,num_col,den_col):returndf.assign(ratiodf[num_col]/df[den_col])# 使用 pipe 链式调用result(pd.read_csv(data.csv).pipe(filter_positive,sales).pipe(add_ratio,profit,sales).groupby(category).agg({ratio:mean}))11.4 实用技巧合集11.4.1 快速查看数据dfpd.DataFrame(np.random.randn(1000,10),columns[fcol_{i}foriinrange(10)])# 快速查看print(df.head())# 前5行print(df.tail())# 后5行print(df.sample(5))# 随机5行print(df.describe())# 统计摘要print(df.info())# 数据信息print(df.dtypes)# 数据类型print(df.shape)# 形状print(df.columns.tolist())# 列名列表print(df.index)# 索引11.4.2 快速选择数据# 快速选择# 选择数值列numeric_colsdf.select_dtypes(include[np.number]).columns# 选择字符串列string_colsdf.select_dtypes(include[object]).columns# 选择列名包含特定字符串的列df.filter(likecol_1)# 选择列名匹配正则表达式的列df.filter(regexcol_[0-5])11.4.3 快速处理缺失值dfpd.DataFrame({A:[1,2,np.nan,4],B:[5,np.nan,np.nan,8],C:[9,10,11,12]})# 快速查看缺失值print(df.isnull().sum())# 每列缺失值数量print(df.isnull().sum().sum())# 总缺失值数量print(df.isnull().mean()*100)# 缺失值百分比# 快速删除print(df.dropna())# 删除包含缺失值的行print(df.dropna(axis1))# 删除包含缺失值的列print(df.dropna(thresh2))# 保留至少2个非缺失值的行# 快速填充print(df.fillna(0))# 用0填充print(df.fillna(df.mean()))# 用均值填充print(df.fillna(methodffill))# 前向填充print(df.fillna(methodbfill))# 后向填充11.4.4 快速数据转换dfpd.DataFrame({A:[1,2,3,4],B:[a,b,c,d],C:[1.5,2.5,3.5,4.5]})# 类型转换print(df.astype({A:float64,C:int32}))# 字符串操作df[B_upper]df[B].str.upper()df[B_len]df[B].str.len()# 数值操作df[A_squared]df[A].pow(2)df[A_log]np.log(df[A])# 条件赋值df[A_category]np.where(df[A]2,high,low)11.5 调试技巧11.5.1 查看中间结果# 使用 pipe 查看中间结果defdebug_print(df,message):print(f\n{message})print(fShape:{df.shape})print(df.head())returndf result(pd.read_csv(data.csv).pipe(debug_print,After loading).query(A 0).pipe(debug_print,After filtering).groupby(B).sum().pipe(debug_print,After grouping))11.5.2 使用选项设置# 显示设置pd.set_option(display.max_rows,100)# 最大显示行数pd.set_option(display.max_columns,50)# 最大显示列数pd.set_option(display.width,200)# 显示宽度pd.set_option(display.float_format,{:.2f}.format)# 浮点数格式# 重置设置pd.reset_option(all)11.6 常见陷阱与解决方案11.6.1 SettingWithCopyWarningdfpd.DataFrame({A:[1,2,3],B:[4,5,6]})# ❌ 警告SettingWithCopyWarningdf[df[A]1][B]100# 可能不生效# ✅ 正确方式1使用 locdf.loc[df[A]1,B]100# ✅ 正确方式2使用 copysubsetdf[df[A]1].copy()subset[B]10011.6.2 索引问题# ❌ 问题重置索引后丢失原索引dfdf.reset_index()# ✅ 保留原索引dfdf.reset_index(dropFalse)# 保留为列dfdf.reset_index(dropTrue)# 完全删除11.6.3 类型推断问题# ❌ 问题整数列有缺失值会变成 floatdfpd.DataFrame({A:[1,2,None,4]})print(df.dtypes)# float64# ✅ 使用 nullable 整数类型dfpd.DataFrame({A:pd.array([1,2,None,4],dtypepd.Int64Dtype())})print(df.dtypes)# Int6411.7 与其他库的集成11.7.1 NumPy# DataFrame 和 NumPy 数组互转dfpd.DataFrame(np.random.randn(100,4),columns[A,B,C,D])arrdf.values# 转 NumPy 数组df2pd.DataFrame(arr,columns[A,B,C,D])# 转 DataFrame# 使用 NumPy 函数print(np.sqrt(df))print(np.log(df))print(np.mean(df,axis0))11.7.2 Matplotlibimportmatplotlib.pyplotasplt dfpd.DataFrame({A:np.random.randn(100).cumsum(),B:np.random.randn(100).cumsum()},indexpd.date_range(2024-01-01,periods100))# 快速绘图df.plot(figsize(10,6))plt.title(Time Series Plot)plt.show()# 子图df.plot(subplotsTrue,figsize(10,8))plt.show()11.7.3 Scikit-learnfromsklearn.preprocessingimportStandardScalerfromsklearn.model_selectionimporttrain_test_split dfpd.DataFrame(np.random.randn(100,4),columns[A,B,C,D])# 数据预处理scalerStandardScaler()df_scaledpd.DataFrame(scaler.fit_transform(df),columnsdf.columns,indexdf.index)# 划分训练集和测试集train,testtrain_test_split(df,test_size0.2)11.8 本章小结核心要点✅性能优化使用向量化操作避免循环选择合适的数据类型使用 eval 和 query✅内存优化分块读取大文件及时删除中间变量使用 category 类型✅链式操作使用方法链提高可读性使用 pipe 自定义函数✅实用技巧快速查看数据快速选择和处理数据调试技巧✅避免陷阱SettingWithCopyWarning索引问题类型推断问题最佳实践清单使用向量化操作选择合适的数据类型使用链式操作提高可读性及时释放内存使用 loc 进行赋值处理大文件时使用分块读取使用 pipe 进行调试
Pandas 高级技巧与最佳实践
发布时间:2026/6/8 17:01:35
Pandas 高级技巧与最佳实践目标掌握 Pandas 的进阶用法和性能优化技巧成为 Pandas 高手。11.1 性能优化11.1.1 向量化 vs 循环importpandasaspdimportnumpyasnpimporttime# 创建大数据集n1_000_000dfpd.DataFrame({A:np.random.randn(n),B:np.random.randn(n)})# ❌ 慢用循环defloop_add(df):result[]foriinrange(len(df)):result.append(df.iloc[i][A]df.iloc[i][B])returnresult starttime.time()loop_resultloop_add(df)print(f循环耗时:{time.time()-start:.2f}秒)# ✅ 快用向量化starttime.time()vector_resultdf[A]df[B]print(f向量化耗时:{time.time()-start:.4f}秒)黄金法则永远不要对 DataFrame 用循环11.1.2 使用合适的数据类型# 创建示例数据dfpd.DataFrame({int64_col:np.random.randint(0,100,1000000),float64_col:np.random.randn(1000000),category_col:np.random.choice([A,B,C,D],1000000),object_col:np.random.choice([北京,上海,广州,深圳],1000000)})print(原始内存使用:)print(df.memory_usage(deepTrue).sum()/1024**2,MB)# 优化数据类型df_optimizeddf.copy()df_optimized[int64_col]df_optimized[int64_col].astype(int32)# int64 → int32df_optimized[float64_col]df_optimized[float64_col].astype(float32)# float64 → float32df_optimized[category_col]df_optimized[category_col].astype(category)df_optimized[object_col]df_optimized[object_col].astype(category)print(\n优化后内存使用:)print(df_optimized.memory_usage(deepTrue).sum()/1024**2,MB)11.1.3 使用 eval 和 query# 创建大数据dfpd.DataFrame(np.random.randn(100000,4),columns[A,B,C,D])# eval高效计算# 普通方式df[E]df[A]df[B]*df[C]-df[D]# eval 方式更快df[E]df.eval(A B * C - D)# query高效筛选# 普通方式resultdf[(df[A]0)(df[B]0)]# query 方式更快resultdf.query(A 0 and B 0)11.2 内存优化11.2.1 分块读取大文件# 分块读取 CSVchunk_size100000chunks[]forchunkinpd.read_csv(large_file.csv,chunksizechunk_size):# 处理每个 chunkprocessedchunk[chunk[value]0]# 示例处理chunks.append(processed)# 合并结果dfpd.concat(chunks,ignore_indexTrue)11.2.2 使用迭代器# 迭代器方式读取forchunkinpd.read_csv(large_file.csv,chunksize10000):forrowinchunk.itertuples():# 处理每一行pass11.2.3 删除中间变量# ❌ 内存占用大df1pd.read_csv(data.csv)df2df1[df1[A]0]df3df2.groupby(B).sum()df4df3.reset_index()# ✅ 及时释放内存dfpd.read_csv(data.csv)dfdf[df[A]0]dfdf.groupby(B).sum()dfdf.reset_index()11.3 链式操作11.3.1 方法链式调用# ❌ 传统方式多个变量dfpd.read_csv(data.csv)dfdf[df[A]0]dfdf.dropna()dfdf.assign(Clambdax:x[A]x[B])dfdf.groupby(D).sum()# ✅ 链式操作一个表达式result(pd.read_csv(data.csv).query(A 0).dropna().assign(Clambdax:x[A]x[B]).groupby(D).sum().reset_index())11.3.2 使用 pipe# 自定义函数deffilter_positive(df,col):returndf[df[col]0]defadd_ratio(df,num_col,den_col):returndf.assign(ratiodf[num_col]/df[den_col])# 使用 pipe 链式调用result(pd.read_csv(data.csv).pipe(filter_positive,sales).pipe(add_ratio,profit,sales).groupby(category).agg({ratio:mean}))11.4 实用技巧合集11.4.1 快速查看数据dfpd.DataFrame(np.random.randn(1000,10),columns[fcol_{i}foriinrange(10)])# 快速查看print(df.head())# 前5行print(df.tail())# 后5行print(df.sample(5))# 随机5行print(df.describe())# 统计摘要print(df.info())# 数据信息print(df.dtypes)# 数据类型print(df.shape)# 形状print(df.columns.tolist())# 列名列表print(df.index)# 索引11.4.2 快速选择数据# 快速选择# 选择数值列numeric_colsdf.select_dtypes(include[np.number]).columns# 选择字符串列string_colsdf.select_dtypes(include[object]).columns# 选择列名包含特定字符串的列df.filter(likecol_1)# 选择列名匹配正则表达式的列df.filter(regexcol_[0-5])11.4.3 快速处理缺失值dfpd.DataFrame({A:[1,2,np.nan,4],B:[5,np.nan,np.nan,8],C:[9,10,11,12]})# 快速查看缺失值print(df.isnull().sum())# 每列缺失值数量print(df.isnull().sum().sum())# 总缺失值数量print(df.isnull().mean()*100)# 缺失值百分比# 快速删除print(df.dropna())# 删除包含缺失值的行print(df.dropna(axis1))# 删除包含缺失值的列print(df.dropna(thresh2))# 保留至少2个非缺失值的行# 快速填充print(df.fillna(0))# 用0填充print(df.fillna(df.mean()))# 用均值填充print(df.fillna(methodffill))# 前向填充print(df.fillna(methodbfill))# 后向填充11.4.4 快速数据转换dfpd.DataFrame({A:[1,2,3,4],B:[a,b,c,d],C:[1.5,2.5,3.5,4.5]})# 类型转换print(df.astype({A:float64,C:int32}))# 字符串操作df[B_upper]df[B].str.upper()df[B_len]df[B].str.len()# 数值操作df[A_squared]df[A].pow(2)df[A_log]np.log(df[A])# 条件赋值df[A_category]np.where(df[A]2,high,low)11.5 调试技巧11.5.1 查看中间结果# 使用 pipe 查看中间结果defdebug_print(df,message):print(f\n{message})print(fShape:{df.shape})print(df.head())returndf result(pd.read_csv(data.csv).pipe(debug_print,After loading).query(A 0).pipe(debug_print,After filtering).groupby(B).sum().pipe(debug_print,After grouping))11.5.2 使用选项设置# 显示设置pd.set_option(display.max_rows,100)# 最大显示行数pd.set_option(display.max_columns,50)# 最大显示列数pd.set_option(display.width,200)# 显示宽度pd.set_option(display.float_format,{:.2f}.format)# 浮点数格式# 重置设置pd.reset_option(all)11.6 常见陷阱与解决方案11.6.1 SettingWithCopyWarningdfpd.DataFrame({A:[1,2,3],B:[4,5,6]})# ❌ 警告SettingWithCopyWarningdf[df[A]1][B]100# 可能不生效# ✅ 正确方式1使用 locdf.loc[df[A]1,B]100# ✅ 正确方式2使用 copysubsetdf[df[A]1].copy()subset[B]10011.6.2 索引问题# ❌ 问题重置索引后丢失原索引dfdf.reset_index()# ✅ 保留原索引dfdf.reset_index(dropFalse)# 保留为列dfdf.reset_index(dropTrue)# 完全删除11.6.3 类型推断问题# ❌ 问题整数列有缺失值会变成 floatdfpd.DataFrame({A:[1,2,None,4]})print(df.dtypes)# float64# ✅ 使用 nullable 整数类型dfpd.DataFrame({A:pd.array([1,2,None,4],dtypepd.Int64Dtype())})print(df.dtypes)# Int6411.7 与其他库的集成11.7.1 NumPy# DataFrame 和 NumPy 数组互转dfpd.DataFrame(np.random.randn(100,4),columns[A,B,C,D])arrdf.values# 转 NumPy 数组df2pd.DataFrame(arr,columns[A,B,C,D])# 转 DataFrame# 使用 NumPy 函数print(np.sqrt(df))print(np.log(df))print(np.mean(df,axis0))11.7.2 Matplotlibimportmatplotlib.pyplotasplt dfpd.DataFrame({A:np.random.randn(100).cumsum(),B:np.random.randn(100).cumsum()},indexpd.date_range(2024-01-01,periods100))# 快速绘图df.plot(figsize(10,6))plt.title(Time Series Plot)plt.show()# 子图df.plot(subplotsTrue,figsize(10,8))plt.show()11.7.3 Scikit-learnfromsklearn.preprocessingimportStandardScalerfromsklearn.model_selectionimporttrain_test_split dfpd.DataFrame(np.random.randn(100,4),columns[A,B,C,D])# 数据预处理scalerStandardScaler()df_scaledpd.DataFrame(scaler.fit_transform(df),columnsdf.columns,indexdf.index)# 划分训练集和测试集train,testtrain_test_split(df,test_size0.2)11.8 本章小结核心要点✅性能优化使用向量化操作避免循环选择合适的数据类型使用 eval 和 query✅内存优化分块读取大文件及时删除中间变量使用 category 类型✅链式操作使用方法链提高可读性使用 pipe 自定义函数✅实用技巧快速查看数据快速选择和处理数据调试技巧✅避免陷阱SettingWithCopyWarning索引问题类型推断问题最佳实践清单使用向量化操作选择合适的数据类型使用链式操作提高可读性及时释放内存使用 loc 进行赋值处理大文件时使用分块读取使用 pipe 进行调试