ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python数据处理与自动化办公实战:两小时掌握高效技能

Python数据处理与自动化办公实战:两小时掌握高效技能 先说个我自己的事。前两年在电商公司做运营分析每月底要对销售、库存、售后三张表做汇总匹配。刚开始我用Excel的VLOOKUP一个个手拖三张表二十多万行拖一次卡五分钟来回折腾七八个小时才弄完还得反复核对有没有匹配错。后来我花了一个周末把整套流程改成了大概七十行的Python脚本从读取原始表、清洗脏数据、匹配汇总到最后生成带格式的Excel报表整个过程从按下回车到拿到结果大概两分半钟。从那以后我体会到一件事Python进阶技巧这东西学到手是真的能实打实减少加班。这篇教程就是围绕数据处理和自动化办公这两个高频场景展开的目标人群是已经掌握Python基础语法、但面对实际问题还不太会下手的读者。我尽量把过程中会踩的坑、底层的原因、可以复用的代码套路都讲透。按照文中的顺序你照着敲一遍、跑一遍两个小时足够掌握一套能直接用于日常工作的实用技能。内容主要覆盖三块pandas做数据清洗和聚合分析、openpyxl和路径处理做自动化办公、以及生成器和装饰器这类能让代码更优雅的进阶语法。每一块都用实际案例说话避免那种“只讲概念不干活”的学习体验。1. 先把环境理清楚进阶打法的前提是“跑起来不卡壳”标题里说“2小时掌握”那时间就不能浪费在装环境和找依赖上。很多人在这一步就卡了大半天回头一看还没开始写代码非常消磨耐心。我把环境准备压缩成一套固定的步骤熟练之后基本十分钟内完事。1.1 环境搭建的正确打开方式如果你电脑上还没装Python直接去官网下载对应系统的安装包。注意一点Windows下安装时务必勾选“Add Python to PATH”这个选项不勾的话后续在命令行里敲python会提示找不到命令到时候还得手动配环境变量纯属给自己找麻烦。装好之后强烈建议创建一个独立的虚拟环境不要把所有第三方库一股脑全局安装。虚拟环境这东西用一句话解释就是给你的每个项目各开一个独立的小房间A项目要用pandas 1.5B项目要用pandas 2.1它们互不干扰不会出现“为了新项目升级库、结果老项目跑不起来”的悲剧。创建虚拟环境的方式我习惯在项目目录下执行python -m venv venv然后激活它。Windows系统venv\Scripts\activatemacOS或Linux系统source venv/bin/activate激活之后命令行提示符前面会出现一个(venv)前缀说明你已经处在虚拟环境里了。接下来安装依赖库pip install pandas openpyxl这里我刻意先只装这两个。pandas负责数据处理openpyxl负责Excel读写它们是本教程的核心武器。其他的库按需再装用多少装多少这样环境始终干净出问题也好排查。1.2 环境配好之后常见的三个坑第一个坑是pip镜像源问题。国内网络环境下直接pip install有时会很慢甚至超时报错。我一般会临时指定清华镜像源pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple这样下载速度会快很多。第二个坑是Python版本太老。pandas新版本需要Python 3.9以上才能安装如果你还在用3.6、3.7这样比较旧的版本建议直接装最新版Python。我早期有一次在一个老项目的环境里跑新代码结果pandas版本不兼容折腾了很久才发现问题源头是Python版本过旧。第三个坑是代码文件编码问题。这个后面还会详细说但环境这个阶段提前打个预防针Windows系统的记事本默认保存编码是GBK而Python默认读文件用的是UTF-8。如果你的脚本里import了某个自己写的模块那个模块是记事本存的执行时大概率会报编码错误。解决办法很简单把代码文件另存为UTF-8编码或者在文件顶部加一行coding声明。2. 数据处理的核心三板斧清洗、变换、聚合数据处理的场景太多了但拆到最底层无非三件事把脏数据洗干净把数据结构变换成分析需要的形态然后分组做统计。这一节我用一套实战案例把这三件事串起来讲代码可以直接照抄去改。2.1 数据读取与初步体检假设你手头有一份销售明细表sales.csv列包括订单号、销售员、产品类别、销售金额、下单日期、退款金额。第一件事永远是读取并“体检”花三分钟看看数据长什么样比直接闷头处理要靠谱得多。import pandas as pd df pd.read_csv(sales.csv, encodingutf-8) print(df.shape) print(df.head()) print(df.info())df.shape输出(行数, 列数)让你直观知道数据规模df.head()显示前几行扫一眼列名和内容有没有异常df.info()会告诉你每一列的数据类型和非空值数量这一步就能看出很多问题。这里要解释一下encoding参数。日常业务数据经常有两个来源一个是从数据库导出的CSV另一个是同事手工整理的Excel另存的CSV。前者多数是UTF-8编码后者若没有特意设置保存出来很可能就是GBK。所以读取CSV时如果报“UnicodeDecodeError”先不要慌把编码换成gbk试试df pd.read_csv(sales.csv, encodinggbk)如果你拿到的不只是CSV还有多个Excel表格也可以用pandas直接统一读取df pd.read_excel(sales.xlsx, sheet_nameSheet1)多条数据要合并时pandas的concat可以做到df1 pd.read_excel(sales_1月.xlsx) df2 pd.read_excel(sales_2月.xlsx) df_all pd.concat([df1, df2], ignore_indexTrue)ignore_indexTrue的意思是重新生成连续的行索引避免两个表合并后索引重复导致之后loc定位混乱。2.2 清洗脏数据完整的一套动作数据体检完之后通常会面临三类脏数据问题缺失值、错误的数据类型、重复记录。我一个个拆开讲。缺失值处理。销售金额为空可能是录入遗漏也可能是退款抵消后的正常情况要先看有多少缺失print(df.isnull().sum())处理缺失值就两条路丢掉或补上。如果缺失行占比很小、而且这些行对整体分析没影响直接dropnadf_clean df.dropna(subset[销售金额])如果某些列是数值型且缺失需要填充最常见的做法是用均值或者中位数填充。这里我推荐中位数而不是均值原因是均值对极端值敏感比如销售金额里有一个异常大单均值会被拉高中位数则更稳健df_clean[销售金额] df_clean[销售金额].fillna(df_clean[销售金额].median())错误数据类型要重点排查。常见问题是“销售金额”这一列看起来是数字但info()显示是object类型。这通常是因为数据里混入了逗号、人民币符号、或者有个别脏字符。解决办法是先把非数字字符清理掉再转换类型df_clean[销售金额] df_clean[销售金额].astype(str).str.replace(,, ).str.replace(¥, ) df_clean[销售金额] pd.to_numeric(df_clean[销售金额], errorscoerce)errorscoerce的含义是转换不过来的值直接变成NaN而不会报错中断。这一步用完之后再info()看一下那一列就会变成float64可以进行加减乘除等运算了。重复记录处理相对简单但要先想清楚“什么算重复”。是订单号完全相同还是所有列都完全相同业务上订单号是唯一标识所以用订单号去重df_clean df_clean.drop_duplicates(subset[订单号], keepfirst)keepfirst表示保留第一条你也可以改成keeplast保留最后一条视业务逻辑而定。日期也要一并处理。如果下单日期是字符串格式排序和按月份聚合都不方便要转成datetime类型df_clean[下单日期] pd.to_datetime(df_clean[下单日期])这样后面就可以直接按月份、季度、年份做聚合了。2.3 数据变换与分组聚合从表到结论的桥梁数据洗好了下一步是做变换和分组统计。这里讲两个最常用的操作透视表pivot_table和分组groupby。按产品类别统计销售额总和用groupby很简单summary df_clean.groupby(产品类别)[销售金额].sum().reset_index()注意groupby之后的结果默认是以“产品类别”为索引的Seriesreset_index把它变回两列的DataFrame更符合日常报表的格式。某个业务中常见的需求是查看每个销售员的订单数、总销售额、平均单笔金额salesman_stats df_clean.groupby(销售员).agg( 订单数(订单号, count), 总销售额(销售金额, sum), 平均单笔(销售金额, mean) ).reset_index()这里agg函数内部用了命名聚合每一行的意思是新列名叫什么对应哪一列用哪个聚合函数。这样一次调用就能完成多种统计不需要写大段循环。透视表则适合做“行是销售员、列是产品类别、值是销售金额总和”的交叉统计pivot pd.pivot_table( df_clean, index销售员, columns产品类别, values销售金额, aggfuncsum, fill_value0 )fill_value0的作用是让没有销售记录的格子显示0而不是NaN表格看起来更规整后续如果要做行或列的合计也更方便。我刻意把透视表和groupby放在一起讲是因为它们经常被拿来做同样的事但在呈现结构上不同。groupby输出的是长表适合机器处理pivot_table输出的是宽表适合人眼阅读。日常我一般先用pivot_table做快速探索再用groupby写进正式的自动化流程里。2.4 实用小技巧列名统一和条件筛选真正干活的时候还有几个高频操作值得单独记一下。改列名。数据表从不同系统导出来列名风格可能差异很大有下划线命名、驼峰命名、中文、英文混搭分析前统一列名能省很多事df_clean df_clean.rename(columns{ sales_name: 销售员, order_no: 订单号 })条件筛选。找出销售金额大于5000的订单big_orders df_clean[df_clean[销售金额] 5000]多条件筛选用和|target df_clean[(df_clean[产品类别] 电子产品) (df_clean[销售金额] 3000)]这里容易犯的错是使用Python的and关键字在DataFrame筛选里不能用必须用而且每个条件都要加括号。我见过不少新人在这一步报错其实原因就是这个细节。按时间筛选。比如只看2024年3月的数据df_clean[下单日期] pd.to_datetime(df_clean[下单日期]) march_data df_clean[(df_clean[下单日期] 2024-03-01) (df_clean[下单日期] 2024-04-01)]用大于等于起始日、小于下月一日的方式比用str.contains去匹配月份字符串要稳得多不会误伤其他字段。3. 自动化办公当Python开始处理Excel、文件夹和批量重命名数据处理到能出结论之后下一步通常就是输出报表、整理文件这类重复劳动。这一节我把自动化办公拆成几个具体场景每个场景给出实用套路。3.1 用pandas一行代码导出Excel报表很多人用pandas做完分析最后导出时的姿势是这样的df_result.to_csv(result.csv, indexFalse)CSV的好处是通用、轻量但如果这个报表要交给业务部门他们大多更希望收到Excel最好还带格式。这里就用得上openpyxl了。pandas配合openpyxl可以一条命令直接输出Excel还可以控制多个Sheetwith pd.ExcelWriter(销售汇总_2024年3月.xlsx, engineopenpyxl) as writer: summary.to_excel(writer, sheet_name汇总, indexFalse) pivot.to_excel(writer, sheet_name透视, indexTrue)这段代码的关键是ExcelWriter。它把多个DataFrame写入同一个Excel文件的不同Sheet。引擎选择openpyxl是因为它对xlsx格式支持最成熟。indexFalse表示不把索引列写进表格让输出更干净透视表那种需要把“产品类别”当作第一列展示的情况保留indexTrue更合适看需求灵活选择。3.2 纯Excel操作openpyxl在pandas不擅长的地方补位pandas处理数据很强但遇到Excel里“把A列字体加粗”“设置列宽”“在第二行插入一行”“合并单元格”这类操作就无能为力了。这种时候要请出openpyxl直接在Excel文件层面操作。举一个实际的例子每到月底要生成一张带标题、带格式的销售排行表。用openpyxl可以这样写from openpyxl import load_workbook from openpyxl.styles import Font, PatternFill, Alignment wb load_workbook(销售汇总_2024年3月.xlsx) ws wb[汇总] ws.insert_rows(1) ws[A1] 2024年3月销售汇总表 ws[A1].font Font(boldTrue, size14) ws[A1].alignment Alignment(horizontalcenter) # 设置列宽让表格适合阅读 ws.column_dimensions[A].width 12 ws.column_dimensions[B].width 20 # 给表头加背景色和加粗 for cell in ws[2]: cell.font Font(boldTrue) cell.fill PatternFill(start_colorD9E1F2, end_colorD9E1F2, fill_typesolid) wb.save(销售汇总_2024年3月_格式化.xlsx)先把pandas生成的数据表打开再用openpyxl做美化——这个“先pandas后openpyxl”的组合拳是我日常处理报表最常用的流程。数据计算交给pandas格式细节交给openpyxl各干各擅长的事代码也容易维护。关于单元格背景色上面代码里用的是十六进制颜色D9E1F2浅蓝色是Excel里一种比较常见的标题底色。如果你想自定义可以在Excel里随便选个颜色然后在填充颜色的自定义里看它的十六进制值抄过来用就行。3.3 批量文件处理路径处理是第一优先级自动化办公另一个高频场景是批量操作文件批量重命名、批量移动、批量压缩。这类操作的核心不是文件本身而是路径处理。很多新人栽在win和mac的路径分隔符差异上还有中英文文件夹名混排导致的转义问题。我建议直接用pathlib它是Python 3.4之后内置的路径处理库写起来直观还能跨平台。批量重命名某个文件夹下所有扩展名为.txt的文件加上日期前缀from pathlib import Path folder Path(待处理文件) for f in folder.glob(*.txt): new_name folder / f20240316_{f.name} f.rename(new_name)folder.glob(*.txt)会返回该目录下所有匹配.txt的文件路径对象。Path对象直接用/运算符拼接路径比字符串拼接优雅得多也不会出现斜杠方向不对的问题。批量移动文件到指定分类目录from pathlib import Path import shutil source Path(下载目录) target Path(归档目录) target.mkdir(exist_okTrue) for f in source.glob(*.pdf): if 发票 in f.name: shutil.move(str(f), str(target / f.name))target.mkdir(exist_okTrue)的意思是如果目标目录不存在就创建它存在则忽略省去了先判断再创建的两步写法。这类脚本写起来很快但有一点要提醒不要直接在原目录上做破坏性操作。早期我写过一个批量改名脚本因为正则表达式出错前缀加错了位置文件被改得一塌糊涂只能靠文件名里的原信息一个一个手工改回来。从那之后我凡是批量操作程序开头一定要先打印前三个文件的新旧名称对比确认无误后再执行真正的rename或move。3.4 Word与PDF办公自动化的另一半版图Excel处理只是自动化办公的一部分Word和PDF也经常碰到。我说两个最常见的需求批量生成Word文档、从PDF里提取文本。批量生成Word常用的是python-docx库。它可以在不手动打开Word的情况下创建文档、写入段落、设置样式。举个例子批量给不同订单生成催款函from docx import Document doc Document() doc.add_heading(催款函, level1) doc.add_paragraph(f尊敬的{company_name}客户) doc.add_paragraph(您于{date}的订单已逾期未付款。请及时处理。) doc.save(f催款函_{order_no}.docx)上面代码里的f-string是Python 3.6之后引入的格式化字符串语法可以直接把变量嵌入字符串中非常方便。如果你的Python版本较老可能不支持f-string那就需要用format方法替代。PDF文本提取是办公自动化的另一个高频需求。批量提取合同PDF里的关键字段可以用pdfplumber库import pdfplumber with pdfplumber.open(合同.pdf) as pdf: first_page pdf.pages[0] text first_page.extract_text() print(text)pdfplumber的extract_text方法返回的是该页的纯文本内容。提取之后配合正则表达式可以进一步筛选特定字段比如合同编号手机号金额等。需要注意的是这类方案只对文本型PDF有效。如果PDF是扫描图片没有文本层任何Python库都直接提不出字来这种情况需要先做OCR识别会复杂很多属于另一个话题了。4. 进阶语法把代码写得更Pythonic数据处理和办公自动化不断写循环代码会越来越长、越来越难维护。进阶技巧里很重要的一个方向就是用更简洁、更高效的方式表达同样的逻辑。这一节我聚焦三个实用点列表推导式、生成器、装饰器。它们不是花哨的语法糖是真的能大幅减少代码行数并提升可读性的工具。4.1 列表推导式三步变一步如果你还习惯于这样写new_list [] for item in old_list: if item 0: new_list.append(item * 2)那么列表推导式可以把它压缩成一行new_list [item * 2 for item in old_list if item 0]列表推导式的结构拆开看是先写要生成什么再写从循环里的哪个变量来最后写筛选条件。顺序上很多人会搞混我习惯记成“先取值表达式再for再if”。实际工作中列表推导式用的最多的地方是数据预处理。比如批量清洗掉字符串首尾空格clean_names [name.strip() for name in raw_names if name]这里的if name会把列表中的NaN值、空字符串、None都过滤掉是一行代码做两步操作的典型用法。列表推导式生成的是列表如果数据量巨大想节省内存可以用生成器表达式把方括号改成圆括号gen (item * 2 for item in old_list if item 0)生成器不会一下子把所有元素都算出来放进内存而是每次迭代才计算一个适合处理大文件时逐行读取的场景。4.2 装饰器为函数统一附加能力装饰器是Python进阶必须掌握的一个特性。一句话解释它的作用在不修改原函数代码的情况下给函数增加额外功能。最经典的例子是统计函数运行时间。我们经常想对比两种数据处理方式哪个更快如果每个函数都写一遍计时代码太繁琐。装饰器可以一次性做成通用工具import time import functools def timer(func): functools.wraps(func) def wrapper(*args, **kwargs): start time.time() result func(*args, **kwargs) end time.time() print(f{func.__name__} 运行耗时: {end - start:.2f}秒) return result return wrapper timer def load_and_process_data(): df pd.read_csv(sales.csv) return df.describe() load_and_process_data()这段代码的关键点有四个一是wrapper接收*args和**kwargs这样任何参数的函数都能被这个装饰器包装二是在wrapper内部先记录开始时间调用原函数拿结果再记录结束时间三是将原函数的返回值在最后return出来否则被装饰的函数会丢失返回值四是functools.wraps用来保留原函数的名称和文档字符串避免调试时函数名全变成wrapper。装饰器还可以扩展出很多用法比如自动重试、权限校验、日志记录等。批量处理Excel文件时加载文件失败自动重试一次这种逻辑用装饰器封装主业务代码会非常干净。4.3 工具函数组合拳lambda配合map和filterlambda表达式是Python里的匿名函数适合那种只使用一次、没必要单独def的逻辑。配合map和filter可以对序列做批量处理nums [1, 2, 3, 4, 5, 6] even_squares list(map(lambda x: x * x, filter(lambda x: x % 2 0, nums))) print(even_squares) # 输出 [4, 16, 36]filter的lambda判断条件保留偶数map的lambda做平方运算生成新序列。这两个函数组合起来一次性完成“筛选变换”配合list转换为列表。不过要提醒一句lambda适合逻辑简单的场景一旦逻辑复杂、超过一行还是老老实实用def定义具名函数可读性会好很多。可读性也是进阶的一个重要评判标准。4.4 函数缓存避免重复计算的利器处理数据时经常遇到同一批数据被反复读取和计算的情况。Python标准库functools里有个lru_cache装饰器能自动缓存函数的计算结果。相同参数再次调用时直接返回缓存不会重复执行函数体from functools import lru_cache lru_cache(maxsize128) def compute_heavy_metric(category): # 假设这里有一段耗时很长的计算 result len(df_clean[df_clean[产品类别] category]) return result compute_heavy_metric(电子产品) compute_heavy_metric(电子产品) # 第二次调用直接命中缓存需要注意的是lru_cache要求函数的参数必须是可哈希的也就是说参数不能是列表或字典这类可变类型。字符串、数字、元组都没问题。另外缓存有maxsize上限超过限制会淘汰最早的数据如果要缓存的内容就是固定几个值把maxsize设为None表示无限制但要小心内存占用。5. 实战项目自动生成月度销售分析报告前面讲的工具和方法最终要在一个完整的项目里串起来才能体现价值。这里我设计了一个非常贴近真实工作场景的实战项目自动读取本月和上月的销售明细表完成清洗、汇总、对比分析最终生成一份包含汇总表、分类别统计、Top销售排行、环比变化等内容的Excel报告并自动命名带日期后缀。5.1 项目需求拆解与代码设计在写代码之前先梳理清楚整个任务需要哪些步骤。我把需求拆成五个模块读取数据加载月销售明细CSV文件清洗数据处理缺失值、重复项、错误类型分析计算计算总销售额、各产品类别汇总、销售员排行榜、环比变化生成报表写入Excel文件的多个Sheet带格式输出对关键行和标题列做字体、底色修饰这种拆解也符合日常项目开发的习惯把一个较大的目标拆成多个小函数每个函数只做一件事。代码结构清晰调试时也能快速定位问题所在。5.2 核心代码实现先写几个模块化的函数。读取和清洗部分import pandas as pd from pathlib import Path from openpyxl import load_workbook from openpyxl.styles import Font, PatternFill def load_sales_data(file_path): df pd.read_csv(file_path, encodingutf-8) df[销售金额] df[销售金额].astype(str).str.replace(,, ).str.replace(¥, ) df[销售金额] pd.to_numeric(df[销售金额], errorscoerce) df[下单日期] pd.to_datetime(df[下单日期]) df df.dropna(subset[销售金额]) df df.drop_duplicates(subset[订单号], keepfirst) return df def process_month(file_path): df load_sales_data(file_path) total_sales df[销售金额].sum() category_summary df.groupby(产品类别)[销售金额].sum().reset_index() top_sales df.groupby(销售员)[销售金额].sum().reset_index().sort_values(销售金额, ascendingFalse).head(10) return total_sales, category_summary, top_sales这里为什么要把“读取和清洗”单独抽出来因为在真实场景里你每个月的数据格式可能都有微小变化可能是多了列可能是字段名变了。单独抽函数改起来只需要动一处不会牵一发动全身。生成报告的部分def generate_report(current_month_file, last_month_file, output_dir): cur_total, cur_cat, cur_top process_month(current_month_file) last_total, last_cat, last_top process_month(last_month_file) mom_change (cur_total - last_total) / last_total * 100 output_path Path(output_dir) / f月度销售报告_{pd.Timestamp.now().strftime(%Y%m%d)}.xlsx with pd.ExcelWriter(output_path, engineopenpyxl) as writer: pd.DataFrame({总销售额: [cur_total], 上月销售额: [last_total], 环比变化率: [f{mom_change:.2f}%]}).to_excel(writer, sheet_name概览, indexFalse) cur_cat.to_excel(writer, sheet_name分类汇总, indexFalse) cur_top.to_excel(writer, sheet_name销售排行, indexFalse) format_report_excel(output_path) print(f报告已生成: {output_path})格式化部分def format_report_excel(path): wb load_workbook(path) for ws in wb.worksheets: ws.column_dimensions[chr(65)].width 20 ws.column_dimensions[chr(66)].width 20 for cell in ws[1]: cell.font Font(boldTrue) cell.fill PatternFill(start_colorD9E1F2, end_colorD9E1F2, fill_typesolid) wb.save(path)这里的chr(65)就是字母Achr(66)就是字母B。chr函数的作用是把Unicode编码转换成对应字符65和66是A和B的编码值所以我这里是在循环设置前两列的列宽为20。如果你有空闲时间研究一下openpyxl会发现它支持更灵活的方式直接设置整列宽度这里用chr是为了展示另一种可用的写法。主函数if __name__ __main__: generate_report( current_month_filerD:\data\sales_202403.csv, last_month_filerD:\data\sales_202402.csv, output_dirrD:\reports )5.3 异常处理与结果验证真实项目中代码不是“跑完就结束”。要养成验证结果的习惯。我每次生成报表之后会做三件事第一检查行数是否匹配。单独打开Excel看录进去的总行数和处理前的数据量是否一致排除漏写或重复写了数据。第二抽查计算逻辑。比如随便选一列已知的销售金额手动加一遍和报表里的合计对一下确认分组统计没有问题。第三把生成结果和上个月的报告格式做对比。有些字段可能因为源数据变化而列数多出来或少了及时调整代码。此外真实场景下数据文件可能缺失或路径写错异常处理也很重要。比如在process_month函数里去捕获文件不存在的异常def load_sales_data(file_path): try: df pd.read_csv(file_path, encodingutf-8) except FileNotFoundError: print(f文件未找到: {file_path}) raise except UnicodeDecodeError: print(f编码错误尝试gbk重新读取: {file_path}) df pd.read_csv(file_path, encodinggbk) ...这样调试起来报错信息会直接告诉你哪个月份的文件出了问题而不是抛一个笼统的异常后一脸懵。这里用到了try...except...else的结构当第一次读取失败时尝试用另一种编码重新读取。这个逻辑在办公场景中非常实用。6. 常见坑位自查编码、路径、索引和性能最后这一节不是凑字数是我自己踩坑踩出来的经验总结。我把数据处理和办公自动化过程中最常遇到的几个问题集中列出来加上解决方式方便你以后排查时一键对照。6.1 编码问题列表症状原因处理方式pandas read_csv报UnicodeDecodeError文件是GBK编码指定encodinggbk代码文件里有中文但运行报SyntaxError脚本不是UTF-8编码另存为UTF-8格式Excel打开CSV乱码CSV是UTF-8但Excel默认GBK输出时加utf-8-sig编码读取数据库导出的文本出现乱码字符集不一致统一转成UTF-8后再处理这里有一个容易被忽视的细节用pandas的to_csv导出UTF-8编码的CSVExcel打开时可能会乱码。原因是Excel默认以GBK解析CSV文件而UTF-8与GBK不兼容。解决办法是导出时用utf-8-sig编码Excel就能正确识别df.to_csv(report.csv, indexFalse, encodingutf-8-sig)utf-8-sig会在文件开头添加一个BOM标记Excel靠这个标记识别文件是UTF-8编码。很多老手也会忽视这个细节但它解决的是个非常让人头疼的乱码问题。6.2 索引和副本相关的隐藏陷阱pandas里有两类操作容易让人吃大亏链式赋值和切片索引。链式赋值简单说就是通过连续索引再赋值例如df[df[销售金额] 0][新列] 1这行代码在某种情况下不会修改原DataFrame反而会抛出一个SettingWithCopyWarning警告。原因是右边的切片可能返回的是一个副本而不是视图你改的是副本原表完全没变代码看起来没报错但结果就是不对。这个警告我在刚用pandas时经常遇到排查了半天才发现赋值没生效。正确的做法是直接用单一层级的loc操作df.loc[df[销售金额] 0, 新列] 1loc支持同时按行条件和列名定位一次性完成筛选和赋值避免把操作链切断了。另一个容易犯的错是用reset_index时忘了drop参数。groupby之后的数据因为索引混乱直接reset_index的话原来的索引会变成一个新列有时候你不想要多余的列df_grouped df.groupby(产品类别)[销售金额].sum().reset_index(dropTrue)加了dropTrue就不会保留旧索引了。如果没加生成的DataFrame里会多出一列索引列稍不留意就可能把这一列当作业务数据带进后续计算。6.3 处理大文件时的内存优化数据量大到内存吃紧时pandas有几个优化思路。最常见的办法是分块读取read_csv的chunksize参数可以控制每次读取的行数把一个大文件拆成多个小批次处理chunk_iter pd.read_csv(big_sales.csv, chunksize10000) total 0 for chunk in chunk_iter: total chunk[销售金额].sum() print(total)这样做的好处是整个文件的占用量不会一次性都放进内存内存紧张的时候能避免程序直接被系统杀掉。另一个优化是使用category类型压缩重复度高的文本列。比如“产品类别”列如果只有几十个不同的值几千行的重复度非常高把它转成category类型能显著降低内存占用同时某些聚合操作还会更快df[产品类别] df[产品类别].astype(category)特别是在处理几百万行级数据时category类型带来的内存缩减非常明显实测可以降到原来的几分之一。6.4 扩展方向定时执行和更多自动化脚本写好了如果每月都要手动跑一次自动化程度其实还差一口气。批量处理完数据后可以配合系统的定时任务让脚本在指定时间自动运行。Windows下可以用任务计划程序macOS和Linux下可以用cron。具体操作网上很多文档我这里不展开但要提一句定时跑脚本时路径一定要写成绝对路径最好不要用相对路径否则定时任务的工作目录可能不是脚本所在目录文件会找不到。如果你有更高阶的需求比如把数据写入数据库用SQL做更复杂的分析可以用sqlite3或pymysql把清洗后的DataFrame写入数据库表import sqlite3 conn sqlite3.connect(sales.db) df.to_sql(sales_clean, conn, if_existsappend, indexFalse) conn.close()如果已经清洗好并计算完毕的表要再配合邮件发送可以尝试用yagmail或smtplib把Excel附件发给相关同事。这样整套工作流就是脚本自动拉数据、自动清洗、自动出报表、自动发邮件人只需要在第一次把脚本写好之后每月只需看一下日志偶尔处理一下异常即可。我自己在搭建这类自动化流水线时一个很深的体会是先跑通一个最简单的完整版本再去追求各种复杂功能。很多人在学到了列表推导式、装饰器等技巧之后总想一步到位把代码写得又短又优雅结果功能没跑通反而把时间耗在调试语法细节上。我的习惯是“先把笨办法写出来确认结果再迭代优化”。这个思路适用所有场景不管是数据处理、办公自动化还是写一个小工具。最后再说一个小技巧写这类脚本我习惯在开头加上一段清晰的注释写明脚本的作用、依赖库和输入输出路径。一个月后再回来维护时你大概率会感谢当时那个写了注释的自己。
返回列表