Pandas实战:告别Excel卡顿,像写SQL一样高效处理大数据
发布时间:2026/10/1 20:40:32来源:尧图网络
你先别急着装依赖包先给你讲个特别常见的场景同事丢过来一个35MB的CSV文件里面是过去三年的订单明细一共83万行。你用Excel打开等了十几秒光标还在转圈。好不容易打开了想按“销售区域”筛一下又卡了快一分钟。你只是想要一个按区域、按月的销售汇总Excel却用“我能行”的眼神反复折磨你。如果你也对这种场景有肌肉记忆那Pandas大概能让你从“Excel难民”直接转变成“数据流水线上的熟练工”。Pandas不是一门新语言它是Python生态里专门做表格数据处理的那个库核心操作思路和你在SQL里写的SELECT、WHERE、GROUP BY极其相似。比起Excel的图形化界面它更像一个“命令行版Excel”你对数据说的每句话都会被精确执行不弹窗、不转圈、不假死。我最早接触Pandas是因为帮一个做运营的朋友合并报表他每天要把十几个Excel汇总成一张总表再跑透视。Excel一旦超过10万行他就得抱着电脑等后来我用Pandas读入、合并、分组聚合原本半小时的活儿十几秒跑完。今天这篇就以“从Excel和SQL迁移过来的人”的视角把Pandas最核心的招法拆开讲透尽量让你今天看完、今天就能上手。1. 为什么是Pandas解开“Excel卡死”与“数据规模”的死结1.1 Excel的卡顿根源不是“软件烂”而是“机制不匹配”很多人以为Excel卡死是因为电脑不行其实不完全是。Excel最大的硬约束是它设计出来是给“人看数据”用的不是给“机器算数据”用的。Excel单个工作表上限是1048576行听着很多但一旦真跑到几十万行大部分操作就开始肉眼可见地变慢。更别提VLOOKUP这种函数它的搜索逻辑在很多场景下需要对查找范围逐行扫描数据量翻倍耗时可能翻四倍甚至更夸张。加上公式联动重算——你改一个单元格整个工作簿里所有依赖它的单元格都要重新算一遍这个连锁反应在大表里是灾难级的。我遇到过最夸张的一次是接手一张带了几十个SUMIF和VLOOKUP的报表总共40万行每次打开需要点“启用编辑”之后等两分钟的公式重算。严格说这不是Excel垃圾而是公式模型的复杂度在大数据量下被放大了。Excel适合做“轻量级交互分析”适合做主数据量在几千到几万行以内、以人工查看和手动筛选为主的分析任务。超过这个规模它就不是“慢一点”而是整个工作模式都不匹配。1.2 Pandas的思路把表格当成“内存中的向量化数组”Pandas之所以能扛住大数据量根本原因在于它把表格加载进内存后所有操作都建立在由NumPy提供的向量化计算之上。所谓向量化就是你对一整个列做运算时底层会并行地在C语言层面把整列数据当作一个数组来处理而不是一行一行地调用Python解释器。你可以这样理解Excel的公式是一格一格去算哪怕你拖动填充柄它本质上还是执行了N次单元格计算而Pandas对一整列做加法、筛选、分组是一次性的批量内存操作。没有公式重算没有单元格联动没有“正在计算(4个处理器)”的进度条只有结果。我随手做一个压力测试给你看。用Pandas生成80万行数据包含区域、品类和金额三列然后按区域加品类分组算总额、均值和订单数import pandas as pd import numpy as np df pd.DataFrame({ region: np.random.choice([华东, 华南, 华北, 西南], 800000), category: np.random.choice([A, B, C], 800000), amount: np.random.randint(10, 5000, 800000).astype(float64) }) result df.groupby([region, category])[amount].agg([sum, mean, count]) print(result.head())这个groupby操作在我的普通办公笔记本上跑完只用了几十毫秒。几十毫秒是什么概念就是你眨一下眼的工夫。同样的事放在Excel里先不谈能不能顺利打开光是插入透视表到刷新的过程通常要按“秒”甚至“分钟”来计时。1.3 什么时候继续用Excel什么时候该切Pandas我这么吹Pandas但也不是劝你把所有工作都搬到Python里。如果你手头数据量一直稳定在5万行以内日常就是筛选、排序、做几个图表给业务看那Excel依然是最快路径因为它的交互性是Pandas比不了的。Pandas的优势场景有三个特征一是数据量大单表经常超过20万行二是流程重复比如每天/每周都要做同样的清洗、合并、汇总三是需要和其他系统对接比如从数据库导出、从接口拉数、和机器学习模型对接。满足任何一个都值得把Pandas纳入工作流。如果三个全占别犹豫这就是Pandas的主场。还有一个很容易被忽略的点Pandas的脚本是可复现的。你在Excel里做20步手工操作做完就没了而Pandas把每一步都写成了代码下次数据更新重新运行一遍就能得到一模一样的结果。这不仅是效率问题更是数据流程的“合规性”问题对需要做审计和回溯的场景尤其重要。2. 像写SQL一样组织Pandas操作——核心语法对照2.1 数据读取与探查SELECT * FROM 表的DataFrame版用Pandas的第一步是读数据。如果你习惯SQL的SELECT * FROM 表名那Pandas里的对应动作就是读取文件然后看一眼内容import pandas as pd df pd.read_excel(sales_2024.xlsx, sheet_nameorders) print(df.shape) # 输出 (行数, 列数) print(df.columns.tolist()) # 列出所有列名 print(df.head(10)) # 看前10行类似 SQL TOP 10 print(df.dtypes) # 查看每列数据类型这里df就是一张常驻内存的表。shape告诉你行数和列数相当于SQL里SELECT COUNT(*)加“查表结构”的合体。head(10)非常实用它不加载全部数据到肉眼只看前10行结构这是Excel打开文件做不到的——Excel必须渲染全部单元格这也是它卡顿的重要来源。我建议你拿到任何DataFrame后先跑一遍这三件套df.shape、df.columns.tolist()、df.dtypes。先知道表多大、有哪些列、每列是什么类型再决定下一步操作。这一步很像SQL里先DESC 表名的感觉。2.2 筛选、排序和去重WHERE、ORDER BY、DISTINCT的直译如果你懂SQLPandas的筛选几乎不用学就是换个写法。SQL是SELECT * FROM orders WHERE amount 500 AND region 华东Pandas对应写成filtered df[(df[amount] 500) (df[region] 华东)]有两个关键点要提醒你。第一多个条件必须用圆括号包起来然后用与、|或、~非连接不能写成Python里的and、or因为Pandas的布尔Series需要逐元素比较。第二df[amount] 500返回的是一个True/False组成的Series它就像一个“筛选面具”放在df[...]里后只有True对应的行会被选中。如果你觉得中括号写法看着累Pandas还提供了query方法写起来更接近SQL的自然语感filtered df.query(amount 500 and region 华东)排序就是SQL里的ORDER BY。Pandas用sort_values最多列排序时往列表里塞多个列名sorted_df df.sort_values([region, amount], ascending[True, False])对应SQL是ORDER BY region ASC, amount DESC。ascending参数传一个布尔列表就能分别控制每一列升序还是降序。去重对应SQL的DISTINCT。单列去重直接看有哪些值unique_regions df[region].drop_duplicates()整行去重指定依据哪些列判断重复deduped df.drop_duplicates(subset[order_id, product_id], keepfirst)keepfirst表示重复时保留第一次出现的行keepFalse表示全部删掉。这对应SQL里的ROW_NUMBER()分组去重思路但比SQL简单得多。2.3 分组聚合GROUP BY的灵魂转译分组聚合是Pandas最像SQL的地方也是取代Excel透视表能力最强的功能。SQL写法是SELECT region, SUM(amount), AVG(amount), COUNT(*) FROM orders GROUP BY regionPandas写成summary df.groupby(region)[amount].agg([sum, mean, count])这一行代码干了三件事按region分组、只取出amount这一列、分别算总和、均值、条数。结果是一个新的DataFrame看起来就是一张家常的汇总表。如果你希望结果更像SQL输出的平铺二维表可以用reset_index()把分组键变成普通列summary df.groupby(region)[amount].agg([sum, mean, count]).reset_index()还能用“命名聚合”让结果列名更好看summary df.groupby(region).agg( total_sales(amount, sum), avg_order(amount, mean), order_count(amount, count) ).reset_index()这种写法和SQL的SELECT region, SUM(amount) AS total_sales语义完全一致。多列分组也很自然组键传一个列表就行summary df.groupby([region, category])[amount].sum().reset_index()我个人的建议是能用groupby加agg解决的需求不要绕道去用透视表因为agg的计算逻辑更透明、更容易排查问题。groupby的性能也通常优于pivot_table尤其分组键数量较多时。2.4 多表连接LEFT JOIN与pd.merge()SQL里最常用的表连接就是JOINPandas的pd.merge几乎一比一复刻了JOIN语义。假设你有订单表orders和促销表promotionsSQL的LEFT JOIN是SELECT a.*, b.discount FROM orders a LEFT JOIN promotions b ON a.promo_id b.promo_idPandas写法merged pd.merge( orders, promotions, onpromo_id, howleft )on指定连接键how指定连接方式。howleft对应LEFT JOINhowinner对应INNER JOINhowright对应RIGHT JOINhowouter对应FULL OUTER JOIN。如果两边的连接键列名不一样用left_on和right_onmerged pd.merge( orders, promotions, left_onpromo_id, right_onid, howleft )说实话我见过很多从Excel转Pandas的人合并数据时第一反应是VLOOKUP思维循环匹配。用merge之后会感叹这才是人干的事。merge是列方向的拼接把两张表的列“横向”合起来如果你要拼接行比如把1月、2月、3月的订单纵向叠在一起就用pd.concatall_data pd.concat([df_jan, df_feb, df_march], ignore_indexTrue)2.5 二维透视透视表与交叉统计Pandas的pivot_table和Excel透视表功能几乎一致但交互性不如Excel胜在自动化和大数据量。例如想统计“各区域在各品类下的销售额”Excel需要拖拽生成透视表Pandas一行搞定pivot pd.pivot_table( df, valuesamount, indexregion, columnscategory, aggfuncsum, fill_value0 )结果的行是区域列是品类交叉点是销售额。aggfunc可以传sum、mean、count甚至传一个函数列表。fill_value0是把空值填成0这个参数在实际报表里特别常用否则你会看到一堆NaN老板看了会皱眉。3. 从Excel迁移到Pandas的实操心法3.1 一遍读完多个Sheet或多个文件日常工作中最常见的痛点不是单表大而是“表太多”。假设你手上有一个Excel文件里面有12个Sheet分别是12个月的销售数据想合并成一张总表xls pd.ExcelFile(2024_sales.xlsx) print(xls.sheet_names) frames [] for sheet in xls.sheet_names: df_sheet xls.parse(sheet) frames.append(df_sheet) all_sales pd.concat(frames, ignore_indexTrue)pd.ExcelFile很聪明它只解析一次文件之后逐个Sheet读取比反复调用pd.read_excel快不少。如果每个月是单独的CSV文件放在同一个文件夹里用glob自动发现文件再合并import glob frames [] for file in glob.glob(sales_*.csv): df_file pd.read_csv(file) frames.append(df_file) all_data pd.concat(frames, ignore_indexTrue)这里提醒一句如果你有几十个文件要合并别一次性pd.concat所有内容。更好的做法是用一个循环边读边筛选把不需要的行提前丢掉最后只合并精简后的结果。这就像搬砖一次搬十块比一次搬一百块更稳。3.2 数据清洗先解决“脏”数据再谈分析Excel里的脏数据有多常见不用我多说空白单元格、文本型的数字、日期格式五花八门、混着单位符号的金额。这些在Excel里还能靠肉眼发现到了Pandas里如果不处理后面全是泪。处理缺失值是两个方向删掉或者填上。如果某一行关键字段缺失直接删除df_clean df.dropna(subset[order_id, amount])如果某列缺失但不影响大局可以填零或填前值df[discount] df[discount].fillna(0) df[amount] df[amount].fillna(methodffill) # 用前一行填充类型混乱是另一个高频坑。Excel里最容易出现的问题是把数字存成了文本比如单元格左上角有个绿色小三角。Pandas读进来后这一列的类型是object而不是数字。处理办法是强制转类型df[amount] pd.to_numeric(df[amount], errorscoerce)errorscoerce的意思是遇到无法转换的值就置为NaN而不是报错中断。日期列同样处理df[order_date] pd.to_datetime(df[order_date], errorscoerce)转换之后建议再检查一遍dtypes和isna()的统计确认没有大量数据被转成NaN。3.3 回写Excel千万别忽略的细节把结果从Pandas写回Excel最基础的是to_excelsummary.to_excel(summary.xlsx, indexFalse)indexFalse太重要了不然Pandas会把行号作为第一列写进Excel别人拿到表格会一脸问号。如果要把多张表写到同一个Excel文件的多个Sheet里用ExcelWriterwith pd.ExcelWriter(report.xlsx, engineopenpyxl) as writer: summary.to_excel(writer, sheet_name汇总, indexFalse) detail.to_excel(writer, sheet_name明细, indexFalse)这里有一个我在实际中踩过的坑如果你直接用pd.read_excel读入一个带格式、带公式的Excel然后to_excel覆盖原文件Excel里的公式和格式会全部丢失。所以我会严格区分“数据源”和“成果物”数据源Excel只读不改成果物一律另存新文件。如果有人需要保留原表和样式最好先在Excel里另存副本再用Pandas操作副本。4. 数据处理提速技巧与性能调优4.1 用向量化代替按行循环接触过Excel的人初学Pandas时最容易犯的一个错误是把Excel的“逐行拖动公式”惯性带进来试图用for循环逐行处理数据。这个习惯一定要尽早改掉。我来做一个直观对比同样是给一个20万行的amount列增加10%的销售额一种方案是循环一种方案是向量化# 慢方案循环逐行修改 df[new_amount] 0 for i in range(len(df)): df.loc[i, new_amount] df.loc[i, amount] * 1.1 # 快方案向量化整列运算 df[new_amount] df[amount] * 1.1循环方案在我的测试机上跑20万行需要十几秒向量化方案是毫秒级差距达到上千倍。为什么因为循环在Python解释器里一行一行跑每一行都要做类型检查、属性查找而向量化把整列交给NumPy底层预编译的C代码一次性完成。这不是优化技巧这是Pandas使用的基本逻辑。如果有些复杂计算实在没法向量化可以用apply比如对每一行基于多个列算一个业务表达式df[score] df.apply( lambda row: row[amount] * 0.6 row[quantity] * 0.4, axis1 )apply比原生for循环快一些但仍然比真正的向量化慢。能直接用列运算解决的就别用apply。4.2 用“数据类型的精准化”给DataFrame瘦身很多Excel转过来的用户不太关注数据类型但数据类型直接决定了内存占用和计算速度。最典型的浪费是把“分类文本”存成了object类型。比如“区域”列只有4个值却有80万行Pandas默认每行都存一个完整的Python字符串对象内存占用惊人。改成category类型Pandas内部用整数编码存储内存能缩小一半以上df[region] df[region].astype(category)如果你想快速看内存占用用这个命令memory_usage df.memory_usage(deepTrue) / (1024 * 1024) print(memory_usage.sum()) # 单位 MB我调优过一个实际案例一张30万行、25列的客户表里面有好几列城市和行业文本内存占用是180MB。把所有低基数列都转成category后降到65MB。虽然这个大小不至于让电脑崩溃但在后续频繁分组和连接时性能差异非常明显。另外把浮点列转成更窄的类型也有帮助比如把默认的float64转成float32精度对报表足够内存减半df[amount] df[amount].astype(float32)4.3 大文件分块读取内存不是无限续杯的如果你要处理的CSV超过几个GB一次性pd.read_csv会把整个文件塞进内存很可能直接把内存吃爆。正确姿势是分块读取。read_csv的chunksize参数会返回一个迭代器每次只读固定行数我们可以边读边处理、边丢弃chunks pd.read_csv(huge_log.csv, chunksize100000) parts [] for chunk in chunks: # 第一步先过滤只保留有用行 filtered chunk[chunk[status] 200] # 第二步聚合 parts.append(filtered.groupby(path).size()) result pd.concat(parts).groupby(level0).sum()这个流程的思路是每一块数据读进来后先尽量缩小体积过滤行、只选需要的列、做局部聚合最后再把精简后的中间结果合并。整个处理过程中内存峰值只取决于“单块大小”和“中间结果大小”而不是整个文件的大小。这个方法解决了我当时一个8GB日志文件的分析问题实属处理大文件的生命线。5. 常见问题与排查技巧实录5.1 读入Excel时日期、表头与空行错乱这类问题在Pandas和Excel交互时极其常见。比如Excel表格前两行是标题和备注第三行才是真正的列名直接读会让数据变成一堆无意义列。解决办法是用header指定表头所在行df pd.read_excel(messy.xlsx, header2)如果表头不是想要的还可以自己指定列名df pd.read_excel(messy.xlsx, headerNone, names[id, date, amount])日期列变成一串数字或字符串常见原因有两种一是Excel里日期被存成文本二是Pandas读入时引擎没有自动识别。统一用pd.to_datetime强制转换df[date] pd.to_datetime(df[date])如果某列突然出现大量NaN先别急着删数据检查是不是Excel里混入了空行或合并单元格。读入后跑一下df.isna().sum()对每一列缺失数量心里有数。5.2 merge后出现重复列或一堆NaNpd.merge的一大坑是当两张表除了连接键还有其他同名列时Pandas会自动生成带_x、_y后缀的列。比如orders和promotions都有一列notesmerge后会变成notes_x和notes_y。如果你没注意后面用notes列就会报KeyError。解决办法是merge之前只保留必要的列promotions_trim promotions[[promo_id, discount]] merged pd.merge(orders, promotions_trim, onpromo_id, howleft)另一个常见问题是merge后出现大量NaN。这通常表示连接键有部分匹配不上比如一边的promo_id是数字另一边是字符串或者一边有空格。排查方法先看唯一值的类型和样本print(orders[promo_id].dtype, promotions[promo_id].dtype) print(orders[promo_id].head()) print(promotions[promo_id].head())类型不一致就用astype统一。有隐藏空格就用str.strip()清理。把键清理干净再mergeNaN基本消失。5.3 让我逢人就推荐的几个“急救代码”最后分享几个我每次处理新数据都会用的小工具代码短小实用。清洗列名把Excel里带空格、带括号的中文列名标准化df.columns df.columns.str.strip().str.replace( , _, regexTrue)一键查看所有列的空值比例missing_ratio df.isna().mean().sort_values(ascendingFalse) print(missing_ratio[missing_ratio 0])快速把全部数字列转成floatnum_cols df.select_dtypes(includeobject).columns for col in num_cols: converted pd.to_numeric(df[col], errorscoerce) df[col] converted把某几列重复值多的文本列统一转为category最大限度降内存for col in [region, category, channel]: if col in df.columns: df[col] df[col].astype(category)这些代码组合在一起哪怕你拿到一张完全陌生的丑表也能在第一轮处理后就把它变成一个“基本能开工”的DataFrame。我个人在实际项目里的体会是Pandas的语法学起来并不难难的是摆脱Excel的“手工操作思维”。你不需要记住所有API只需要记住一个大方向——把数据当作一个整体用声明式的语法告诉它“要什么”而不是用循环告诉它“每一步怎么做”。一旦你想通了这一点Pandas就会从“又一个工具”变成“离不开的伙伴”。下次再遇到Excel卡死不用砸电脑先把数据交给Pandas试试。
网站建设高端定制企业官网