ARTICLE DETAIL

资讯详情

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

pandas数据分析实战:从环境配置到清洗与可视化的完整指南

pandas数据分析实战:从环境配置到清洗与可视化的完整指南 做数据分析的同学十有八九是从pandas开始接触Python的。我也一样当年第一次把Excel表格读进DataFrame时感觉整个人都轻松了——原来批量处理几十万行数据可以这么快。但实际用起来pandas的坑一点不少环境装不上、类型转不对、正则表达式死活匹配不上甚至很多人在ArcGIS Pro里想用pandas却不知道它到底装没装。这篇东西不是官方文档的复读而是我这几年代码里踩出来的经验总结。你会看到PyCharm和ArcGIS Pro里的安装细节、Series和DataFrame的创建逻辑、清洗环节最常用的类型转换和正则操作、文本文件和Excel的读写要点还有ewm指数加权平均和Matplotlib的视觉化练习。适合刚开始学pandas的人也适合写了一大堆代码但还是经常被bug绊住的老手。1. 环境准备pandas装不上怎么办从PyCharm到ArcGIS Pro的实战1.1 PyCharm中安装pandas的三种可靠姿势很多新手在PyCharm里装pandas第一反应就是打开Terminal敲pip install pandas结果要么提示pip不是内部或外部命令要么直接报Connection error。先说最标准的做法打开PyCharm的File - Settings - Project - Python Interpreter点右侧的“”号搜索pandas选中后点击Install Package。这个图形化操作会调用当前解释器对应的pip安装完成后在项目里就能直接import pandas as pd。但图形界面偶尔也会卡住尤其是公司网络有隔离的时候。这时候建议直接用命令在PyCharm底部Terminal里执行python -m pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple换成国内镜像速度会快很多。注意这里的python -m pip比直接pip更安全它能确保把包装到你当前选中的那个Python解释器里而不是系统里另一个Python版本。还有一种情况项目用conda环境那么应该用conda install pandas而不是pip避免环境内出现依赖冲突。装完记得验证一下版本在命令行里执行python -c import pandas; print(pandas.__version__)。我遇到过不少朋友说“装好了但import还是报错”十有八九是PyCharm里选了解释器A但Terminal的Python指向了解释器B。检查这个特别快但特别容易忽略。PyCharm左下角的Python Interpreters设置里一定要确认你当前项目用的解释器和你安装包时用的解释器是同一个。1.2 ArcGIS Pro里到底装没装pandas这个问题我收到过很多次。ArcGIS Pro自带了一个Python环境一般叫arcgispro-py3在这个环境里pandas通常是已经装好的不需要你额外安装。你可以在ArcGIS Pro里打开Python窗口直接输入import pandas试试能正常导入就说明有。但现实中很多人不是直接在ArcGIS Pro的Python窗口里跑而是用外部IDE想调用ArcGIS Pro的Python解释器这时候就会出各种奇怪的问题。如果你用的是ArcGIS Pro自带的Python环境请务必不要用pip直接往里面乱装包因为ArcGIS Pro管的很严容易把环境搞乱。正确方法是使用ArcGIS Pro自带的Python Package Manager你在软件的主菜单里能找到“Python”设置里面可以搜索pandas查看已装版本。如果需要更新或安装其他包也建议在那个管理器里操作而不是自己开个cmd就pip install。至于“arcgis pro中安装pandas了吗”这种搜索多半是用户想确定能否在ArcGIS Pro里做数据分析。我的建议是直接用自带的pandas没问题但版本可能不是最新。如果你需要一些较新的pandas功能可以用投影里的Python Package Manager去更新pandas。如果更新后ArcGIS Pro报错那就果断回退到之前的版本——毕竟ArcGIS Pro的很多地理处理工具要靠pandas更新太快反而容易踩兼容性的雷。这个过程我试过结论就是能用就行别追求最新。2. 数据结构创建Series和DataFrame怎么建最顺手2.1 Series创建的5种方式pandas最底层的结构是Series你可以把它理解成带标签的一维数组。创建Series最常用的是传一个列表比如pd.Series([1, 2, 3])索引默认是从0开始的整数。另一种常用方式是从字典创建字典中的键会成为索引值成为数据。还有一种是从标量创建比如pd.Series(5, index[a, b])会生成两个都是5的行。很多人不知道还可以从NumPy数组创建当你已经有一个numpy数组时直接包一层Series就行。需要注意的一个细节是dtype。创建Series时最好显式指定类型比如pd.Series([1, 2, 3], dtypeint64)否则你会得到一个object类型的Series后续计算时会很痛苦。我经常看见有人创建的Series显示dtype: object然后想直接.mean()结果报错这就是一开始没指定类型的问题。还有一个搭配日期非常常用的技巧就是用pd.date_range生成索引。你可以在创建Series之前在index参数里传入日期范围比如indexpd.date_range(2024-01-01, periods5, freqD)。这种带时间索引的Series后面做重采样、画图都特别方便。创建Series本身不难但很多人忽略了name参数——如果你希望这个Series后面能顺利变成DataFrame的一列提前给它一个名字name会省掉很多麻烦。2.2 DataFrame创建时的常用参数与坑DataFrame就是二维表格结构创建方式比Series更多。最常用的当然是pd.DataFrame({列名: [数据], 另一列: [数据]})。这种字典方式键是列名值是整列数据。如果数据是嵌套字典{第一层: {第二层: 值}}pandas会自动把内层键变成索引。直接传入一个列表的列表像pd.DataFrame([[1, 2], [3, 4]], columns[A, B])也很常见。这里特别容易犯的错误是忘了指定columns结果列名就变成了0和1。还有从列表字典构造时如果列表长度不一样pandas会用NaN填充缺的列这是默认行为但如果你不想让它自动补NaN就需要手动处理好数据长度。创建DataFrame时index参数和columns参数的联动关系需要理清。比如你想创建个空表pd.DataFrame(columns[A, B])这是可以的但之后再往里一行行追加数据会很慢不太推荐。更好的做法是先准备一个列表把所有行都放进列表里最后一次性创建DataFrame。我在实际项目中深有体会——如果数据量是几万行用append或者loc一行行加性能差到你想砸电脑一次性构建会快很多。3. 数据类型转换与正则表达式清洗环节的两大杀器3.1 类型转换astype()和pd.to_numeric怎么选pandas里的数据类型有时候很“狡猾”看起来是数字实际却是字符串。最常见的坑是从Excel读进来的数字列可能带着空格或者空格被读成了NaN。这时候需要类型转换。最直接的方法是df[列].astype(int)但它非常严格只要有非数字字符就会报错。所以更推荐用pd.to_numeric它有一个errors参数可以设置为coerce把不能转换的变成NaN而不是让整个程序崩溃。我之前处理过一个数据报表里面有一列金额混着中文逗号和单位“万元”。直接astype就挂了后来我用pd.to_numeric(df[金额], errorscoerce)再配合后面要讲的正则表达式把“元”“万”等后缀去掉才算清理干净。还有一个经验是字符串列转日期尽量别用astype用pd.to_datetime它会自动识别各种格式比如2024-01-01、2024/01/01、2024年1月1日等。当然也有识别不了的可以用format参数指定格式比如format%Y/%m/%d。值得一提的是astype在pandas 2.0之后对字符串类型有个新推荐astype(string)这是pandas自己的字符串类型比Python原生str类型好使不会出现NaN变成字符串nan的尴尬。我现在的建议是遇到分不清的列先print(df.dtypes)再print(df.head())然后决定用哪种转换。这个习惯能省掉一堆莫名的报错。3.2 正则表达式在pandas文本处理中的使用正则表达式在pandas里的应用主要体现在字符串方法上str.contains、str.extract、str.replace。比如你有一个“姓名_省份”这样的列想拆出省份用df[列].str.extract(r_(.*))就行。注意在正则模式前一定要加r表示原始字符串否则反斜杠会被转义导致匹配失败。很多新手在str.contains里直接写普通字符串然后发现没匹配上。其实str.contains默认是支持正则的所以如果你想匹配括号这种特殊字符必须写\(而不是(。如果不想处理正则语法可以把参数regexFalse传进去这样就会按普通字符串匹配性能还更好。我还经常用正则表达式做数据校验比如过滤出手机号列里格式错误的数据。写一个df[df[手机号].str.fullmatch(r1\d{10})]能快速找出不是11位数字且不是1开头的行。str.fullmatch是整列匹配整个字符串比str.match更严格不容易误判。清洗时如果正则写复杂了建议先在小的Series上测试用df[列].str.contains(...).head()验证结果再运行全量。4. 数据清洗基本操作去重、缺失值与文本整理4.1 缺失值处理的正确顺序清洗数据时缺失值处理顺序很重要。我的套路是先看概览——用df.info()或df.isna().sum()统计每列缺失数量然后决定是删还是填。填缺失值常用df.fillna()但无脑填0是不对的。如果是数值型数据可以用df[列].mean()或df[列].median()填充这样不会引入极端偏差如果是类别型数据可以考虑用“缺失”这个类别填充或者用众数mode()填充。有时候缺失值不是NaN而是空字符串或None。这个很容易被忽略。我遇到过一个数据文件里面全是nan字符串。所以清洗第一步最好把常见的缺失表示都统一掉比如df.replace([None, ], np.nan, inplaceTrue)。否则你后面用dropna删不掉。删除缺失值的时候dropna的subset参数特别有用。比如你有100列只想根据某几个关键列是否缺失来决定是否删除整行那就写df.dropna(subset[关键列1, 关键列2])。还有一个值得记的参数是how默认是any只要有一列缺失就删行如果改成all就表示只有当整行都是缺失值才删除。这个在数据很稀疏的场景下很实用。4.2 重复值判断与删除的细节重复值是清洗环节绕不开的。判断重复最常用df.duplicated()返回一个布尔序列标记哪些行是重复的。这里有个细节duplicated()默认把第一次出现的行标记为False后面的重复行标记为True。如果你不关心保留哪一行直接用df.drop_duplicates()就行。如果想保留最后一次出现的可以加参数keeplast。但实际业务里重复的定义往往不是整行完全一样而是某些关键字段重复。这时就要用subset参数比如df.drop_duplicates(subset[用户ID], keepfirst)效果是保留用户ID第一次出现的行删除后面同ID的行。这样处理比先排序再删除更干净。我还见过一种情况看似重复的行实际上是因为字符串头尾有空格。比如 张三和张三会被当成两个不同的值。清洗时先对涉及重复判断的列做str.strip()再去重否则你删了半天也删不干净。所以去重的顺序是先清洗文本格式再定义重复键最后再去重。4.3 文本列清洗的标准套路文本列清洗是所有数据工作里最磨人的环节。常见操作有转小写str.lower()、去除头尾空格str.strip()、把中文括号替换成英文括号str.replace(, ()、把全角和半角统一起来。很多文本问题不是程序上的而是录入时的不规范。比如“联系电话”里塞着“-”或空格先用正则替换掉再统一转成字符串类型。我自己的标准流程是先用astype(string)把列转成pandas字符串类型然后str.strip()再用str.replace处理特殊字符最后用str.extract或str.split提取需要的字段。文本清洗特别需要检查的是替换的正则有没有影响到正确数据例如删掉“-”时会不会把日期里的横杠也删了。所以我建议“先局部测试再全量运行”。不要忘了把清洗后的列再赋值回原DataFrame很多新手写df[列].str.strip()以为就改了原数据其实没保存。必须写成df[列] df[列].str.strip()。这种小失误很容易排查但也容易反复。5. 文件读写文本文件和Excel的全部要点5.1 读写文本文件sep、encoding、header这些参数别搞错用pandas读文本文件最常见的一定是pd.read_csv。但CSV这个词其实很宽泛分隔符不一定是逗号可能是tab、分号甚至是空格。所以第一步是确认sep参数。我经常看见有人读TSV文件没指定sep\t导致整列被读成一个字符串。建议先打开文件看一眼再设置分隔符。另一个高频问题是编码。用Windows生成的文本文件很多时候是gbk或gb2312编码如果你直接pd.read_csv(文件名.csv)会用默认的utf-8去解析然后报UnicodeDecodeError。这时候加一个encodinggbk就好了。也有可能是gb18030它是gbk的超集更保险。实在不确定编码可以用open(文件名, r, encodingutf-8, errorsreplace)看前几行然后再返回pandas读。读写的时候header参数也很关键。如果文件没有表头你要设置headerNone并手动指定names[列1, 列2]如果文件表头在前面几行而且前面有说明文字可以用skiprowsn跳过。我处理过一份报告前两行是标题和日期第三行才是列名于是我用skiprows1让第二行变成表头。写文件时同理df.to_csv(输出.csv, indexFalse)一定要设置indexFalse否则你会凭空多出一列“Unnamed:0”每次都要手动删。5.2 读写Excelengine选型与常见报错Excel读写也是pandas的强项但坑也不少。读取用pd.read_excel(文件.xlsx, sheet_nameSheet1)其中sheet_name可以传单个字符串也可以传[Sheet1,Sheet2]传列表时会返回一个字典键是工作表名值是DataFrame。如果对性能有要求可以加参数engineopenpyxl这是处理xlsx文件的标准引擎。写入Excel时如果只想写入一个sheet用df.to_excel(输出.xlsx, sheet_name数据, indexFalse)。但如果一个文件要写多个sheet就要用pd.ExcelWriter来管理。我写过最典型的一个场景一个年度报表里有12个月的数据每个sheet一个月用ExcelWriter逐月写入最后一次性保存非常方便。注意先writer.save()再关闭否则文件会损坏。还有两个常见的报错ModuleNotFoundError: No module named openpyxl和No module named xlrd。这表示没有安装对应的Excel引擎。Excel文件的话读和写都需要openpyxl旧版xls文件读取需要xlrd。建议直接在PyCharm里按前面说的方式安装openpyxl。在ArcGIS Pro环境里如果读Excel报错也可以用它的Package Manager安装openpyxl。总之Excel引擎装不全会是最常见的坑。6. 高级计算与可视化ewm函数和Matplotlib联合作业6.1 ewm指数加权移动平均参数详解与选择逻辑ewm函数全称是Exponentially Weighted Moving Average中文就是指数加权移动平均常用于时间序列平滑。很多教科书里只提一个span参数但实际应用中还会碰到com、halflife、alpha这三个参数容易让人晕。这四个参数其实是等价的都可以用来定义衰减因子只不过表达方式不同。alpha是直接的衰减因子值越大历史权重衰减越快。span是另一种表达约等于“跨度”和alpha的关系是alpha 2/(span1)。com则是从中心点角度定义的alpha 1/(1com)。halflife指的是权重衰减到一半需要多少时间周期更直观。我推荐大家平时用span或者halflife因为它们更贴近业务直觉。比如你要算“过去7天的移动平均”用span7更直接。还有一个重要参数是adjust默认是True此时会从开始位置就考虑所有历史点并用衰减系数修正初始比例如果是False则从开始位置起旧点的权重会迅速减小但在序列开头的新点响应更灵敏。实际做策略回测时很多人会把adjustFalse当成快速反应的平滑器用效果很好。使用ewm时别忘了min_periods它表示在输出NaN之前需要多少个非丢失值。有时候数据开头有缺失如果你设置min_periods5前4个点都不会有输出可以避免因为数据太少而计算出来的值太失真。我踩过坑用ewm预测时没设min_periods导致序列开头出现极端值最后还得重新清洗一遍。6.2 pandasMatplotlib的练习套路pandas和Matplotlib几乎是天生的搭档。最简单的练习就是读取一个时间序列数据然后直接df.plot()。pandas的Series和DataFrame都内置了plot()方法它会自动调用Matplotlib。但很多人画完图发现中文乱码这其实是Matplotlib字体设置的问题。解决的万金油写法是import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False在Windows上SimHei黑体一般都有设置完中文就没问题了。如果你是Mac可以把SimHei换成Arial Unicode MS或者PingFang SC。如果发现图里负号显示不出来的“方块”基本都是没设置axes.unicode_minus。做练习的时候推荐先用df.describe()看数据分布再用df.plot(kindline)画折线然后试试kindbar画柱状图kindhist画直方图kindscatter画散点图。pandas的plot方法已经封装了大部分常用类型省去很多写Matplotlib底层代码的麻烦。不过如果你想调整图例、标记点、颜色就得学习一下Matplotlib的API。比如df.plot()返回的坐标轴对象可以继续设置标题、轴标签等。我建议的练习流程是先用pandas做数据清洗把日期列转成索引再按月份resample(M).sum()聚合最后绘图。这套组合是数据分析最常见的链路。如果你要在一个图里同时展示多个列直接df[[列1, 列2]].plot()就行pandas会自动分线。还有一个技巧是创建多个子图用plt.subplots()先创建画布和子图数组再把每个子图传给对应DataFrame的ax参数。这种逻辑和直接展示多列不同更适合各指标量纲不一样的场景。7. 常见问题速查与避坑心得7.1 高频报错整理报错信息可能原因解决办法ModuleNotFoundError: No module named pandas解释器不匹配或未安装检查PyCharm解释器重新安装UnicodeDecodeError文件编码不是utf-8指定encodinggbk或gb18030KeyError: 某列名列名拼写错误或不存在先print(df.columns)核实ValueError: cannot convert float NaN to integer整数列里有NaN先填充NaN或转为float再处理ImportError: Missing optional dependency openpyxl缺少Excel引擎安装openpyxlAttributeError: DataFrame object has no attribute appendpandas 2.0后移除了append方法用pd.concat或先构造列表这些报错在初学者中几乎每天都能看到。与其死记不如建立一套排查顺序先看报错最后一行是什么再回看是哪一步操作引起的最后用df.head()、df.dtypes去检查数据状态。我发现很多问题不是代码写错而是数据跟预期不一样比如列名里多了空格或者预期是数字的列其实是字符串。所以排查时先看数据再看代码。7.2 我踩过的几个坑第一用df.apply时往函数里传入了一个字符串但我忘记函数内部要处理的是整个Series。比如我写过df.apply(lambda x: x[列].strip())结果x是DataFrame的每列而不是每行调试了半天。后来我记住了如果对列处理应该直接对列名操作如果对每行处理要用参数axis1。第二正则表达式里括号的坑。我首次写str.extract((.*))时没加r然后直接匹配字符串里的“转义字符”结果全乱了。后来养成习惯所有正则模式前面都加r哪怕只是普通字符。这个习惯帮我省了大量时间。第三处理时间序列时没有先将日期列设为索引就调用resample结果一直报错。后来我才知道resample要求索引是时间类型否则会报类型错误。现在我会先执行df[日期] pd.to_datetime(df[日期])再df df.set_index(日期)然后才能流畅地做重采样。第四Excel导出后打开文件发现中文变成了乱码或变成“口口口”。这个其实是Excel自身显示问题pandas写入时默认UTF-8Excel在某些系统上需要BOM头。解决办法是写CSV时用encodingutf-8-sig带BOM的UTF-8格式Excel能正确识别。如果是写Excel文件一般不会有乱码问题但推荐设置一下engineopenpyxl兼容性更好。7.3 写在最后的建议如果你刚开始接触pandas别急着堆功能先把今天讲的几个核心场景练熟数据结构创建、类型转换、文本处理、文件读写。每个功能不用记全参数记住“什么场景用什么功能”就行。比如看到日期就想到pd.to_datetime看到文本清洗就想到.str系列看到时序就想到resample和ewm。我个人印象最深的一次是帮同事清洗一份十几万行的对账数据表头不统一金额带着货币符号日期有各种格式还有大量重复。如果没有pandas的类型转换和正则表达式手动处理可能得加班一整晚但用pandas后我写了一个20行左右的脚本几分钟就完成了。那一刻我真正意识到pandas不只是一个工具更像是一条流水线把脏乱差的数据一步一步变成可以分析的漂亮表格。所以最后再分享一个小技巧动手写任何pandas代码前先把数据打印出来看一眼。print(df.head())和print(df.columns)这两个操作比任何代码调试都能更快帮你定位问题。数据对了代码自然就顺了。
返回列表