尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Python数据分析实战:Pandas数据清洗、处理与聚合核心技巧

Python数据分析实战:Pandas数据清洗、处理与聚合核心技巧 1. 从“数据沼泽”到“数据绿洲”为什么你离不开pandas如果你刚接触Python数据分析或者已经写了几百行代码但每次处理Excel、CSV数据时依然感觉像是在泥潭里挣扎——打开文件、复制粘贴、手动筛选、写一堆循环计算最后还可能因为一个格式错误前功尽弃。那么今天聊的这个工具就是把你从“数据沼泽”里捞出来的那根绳子。我说的就是pandas。它不是动物园里那只黑白相间的萌物而是一个基于Python的、开源的、专门为数据分析而生的库。它的名字源于“Panel Data”面板数据但你现在可以简单理解为“Python Data Analysis”的缩写。在数据科学和商业分析的圈子里pandas的地位就像木匠手里的锤子厨师手里的菜刀是吃饭的家伙是基础中的基础。为什么它如此重要因为数据从来不是以“干净、规整、随时可用”的姿态出现的。你从业务系统导出的Excel可能夹杂着合并单元格、空行和莫名其妙的“N/A”文本你从网页爬下来的数据可能日期格式千奇百怪数字里混着中文逗号。pandas的核心价值就是提供了一套高效、统一、直观的接口让你能用几行代码完成过去在Excel里需要手动操作半小时甚至写几十行复杂循环才能完成的数据清洗、转换和分析工作。我见过太多新手一上来就想搞机器学习、深度学习结果卡在数据预处理的第一步被各种格式问题折磨得怀疑人生。其实数据分析80%的时间都花在数据准备上而pandas就是帮你把这80%的时间压缩到20%的利器。它让你能专注于分析逻辑和业务洞察而不是和数据的“脏乱差”做无谓的搏斗。接下来的内容我会抛开那些厚厚的官方文档和教科书式的罗列直接带你上手最常用、最高频的pandas代码片段。这些代码不是孤立的命令而是我多年在实际项目中反复使用、验证过的“组合拳”。我会解释每一行代码背后的意图告诉你什么场景下该用哪个方法以及我最常踩的那些坑。我们的目标不是背API而是让你真正理解如何用pandas的思维像搭积木一样高效地解决真实的数据问题。2. 万丈高楼平地起数据读写的“正确姿势”数据分析的第一步永远是把数据“弄进来”。pandas支持读取几乎任何你能想到的格式CSV、Excel、JSON、SQL数据库、HTML表格甚至剪贴板。但“能读”和“读得好”是两回事。一个错误的参数可能让你后续的分析全盘皆错。2.1 读取CSV与Excel细节决定成败CSV和Excel是最常见的数据源。用pd.read_csv()和pd.read_excel()看似简单但魔鬼藏在参数里。import pandas as pd # 基础读取 df_csv pd.read_csv(data.csv) df_excel pd.read_excel(data.xlsx, sheet_nameSheet1)这行代码能跑通但很脆弱。真实的数据文件往往带着各种“惊喜”。场景一编码问题——中文乱码的罪魁祸首如果你的CSV文件里有中文打开后发现是“锟斤拷”之类的乱码十有八九是编码问题。Windows系统下生成的CSV常用gbk或gb2312编码而read_csv默认使用utf-8。# 尝试指定编码 df pd.read_csv(data.csv, encodinggbk) # 如果还不行试试常见的其他编码 # df pd.read_csv(data.csv, encodinggb2312) # df pd.read_csv(data.csv, encodingutf-8-sig)提示一个快速判断编码的小技巧是用记事本打开文件然后点击“文件”-“另存为”在保存对话框底部可以看到当前文件的编码格式。场景二表头不在第一行有些导出的数据前几行是说明信息真正的表头在第4行。df pd.read_csv(data.csv, header3) # 指定第4行0-based索引作为列名场景三没有表头需要自己指定数据文件就是纯数据没有列名。# 方法1读取时不指定列名pandas会自动分配0,1,2... df pd.read_csv(data.csv, headerNone) # 方法2读取时直接指定列名推荐更清晰 df pd.read_csv(data.csv, headerNone, names[日期, 销售额, 门店, 产品])场景四需要读取特定列文件很大有几十列但你只关心其中几列。df pd.read_csv(data.csv, usecols[日期, 销售额, 产品])这样做不仅能节省内存还能加快读取速度尤其是在处理大型文件时。场景五处理“脏”数据数据里可能有缺失值用“-”、“NA”、“NULL”等表示希望pandas能自动识别为NaN。df pd.read_csv(data.csv, na_values[-, NA, NULL, ])对于Excel文件还有一个常见坑是“数据类型推断”。Excel里一个单元格看起来是数字但可能存储为文本。pandas读取时如果一列里混有数字和文本整列可能会被识别为object类型影响后续计算。# 读取时指定某列为字符串类型 df pd.read_excel(data.xlsx, dtype{员工工号: str})2.2 数据预览与基本信息探查你的第一份“体检报告”数据读进来了别急着分析。先给它做个体检了解它的“身体状况”。# 1. 查看前5行和后5行 print(df.head()) # 默认前5行 print(df.tail(3)) # 查看后3行 # 2. 查看数据形状行数列数 print(df.shape) # 输出 (100, 5) 表示100行5列 # 3. 查看列名、数据类型和非空值数量 print(df.info())df.info()是我最常用的初步诊断工具。它能一眼告诉你每列的名称。每列的数据类型int64,float64,object等。object类型通常是字符串或混合类型需要警惕。每列的非空值数量。如果非空数远小于总行数说明这列存在大量缺失值。内存占用。对于大数据集这个信息很重要。一个真实的踩坑案例我曾分析一个用户行为数据集df.info()显示“用户ID”列是object类型。我没在意直接开始分组统计。结果发现分组数量巨大性能极差。最后才发现这列数据里混入了少数几个像“123-abc”这样的字符串ID导致pandas将整列判定为文本。用df[‘用户ID’].unique()[:20]快速查看一些唯一值后才定位到问题。解决方法是用errors’coerce’参数尝试转换将无法转换的设为NaN。# 4. 查看数值型列的快速统计摘要 print(df.describe())df.describe()默认只针对数值列int和float给出计数、均值、标准差、最小值、四分位数和最大值。它能帮你快速发现异常值比如销售额有负数或者年龄出现了999这样的离谱值。# 5. 查看所有列包括非数值列的统计摘要 print(df.describe(includeall))2.3 数据写出保存你的劳动成果处理完的数据总要保存下来。最常用的还是CSV和Excel。# 保存为CSV df.to_csv(cleaned_data.csv, indexFalse, encodingutf-8-sig) # 保存为Excel df.to_excel(report.xlsx, indexFalse, sheet_name月度报告)关键参数解析indexFalse强烈建议加上。如果不加pandas会把行索引0,1,2…也作为一列写入文件这在绝大多数情况下都是多余的还会让接手的同事困惑。encoding’utf-8-sig’保存CSV时使用带BOM的UTF-8编码可以确保在Windows的Excel中打开时中文字符正常显示不会乱码。sheet_name指定Excel工作表的名字。3. 数据清洗与预处理从“毛坯房”到“精装修”原始数据就像毛坯房直接没法住人。数据清洗就是装修是最耗时但也最体现功力的环节。3.1 处理缺失值面对“空白”的哲学数据缺失是常态。处理方式无非三种删除、填充、保留。选择哪种取决于业务逻辑和缺失比例。1探查缺失情况# 查看每列缺失值的数量 print(df.isnull().sum()) # 查看每列缺失值的比例更直观 print(df.isnull().sum() / len(df) * 100)2删除缺失值最简单粗暴也最可能丢失信息。适用于缺失比例极低或该行/列确实不重要的情况。# 删除任何包含缺失值的行 df_dropped_rows df.dropna() # 删除任何包含缺失值的列 df_dropped_cols df.dropna(axis1) # 只删除在‘销售额’和‘成本’这两列上同时缺失的行 df_dropped_specific df.dropna(subset[销售额, 成本])3填充缺失值更常用的方法。填充什么值需要思考。# 用固定值填充例如用0填充 df_filled_0 df.fillna(0) # 用前向填充用上一个有效值填充 df_filled_ffill df.fillna(methodffill) # 用后向填充用下一个有效值填充 df_filled_bfill df.fillna(methodbfill) # 用该列的统计值填充例如用均值填充‘年龄’ mean_age df[年龄].mean() df[年龄].fillna(mean_age, inplaceTrue) # inplaceTrue表示直接修改原df # 分组填充更高级的方法。例如不同城市的平均工资不同缺失的工资用该城市的平均工资填充 df[工资] df.groupby(城市)[工资].transform(lambda x: x.fillna(x.mean()))注意inplaceTrue参数会直接修改原始的DataFrame操作不可逆。对于重要的数据清洗步骤我个人的习惯是尽量不使用inplaceTrue而是将结果赋值给一个新变量如df_cleaned df.fillna(...)。这样保留了原始数据的副本方便回溯和对比。只有在确定操作无误且原始数据不再需要时才考虑使用inplaceTrue。3.2 处理重复值消灭“双胞胎”重复数据会扭曲分析结果比如让销售总额虚高。# 查看重复行所有列值完全相同的行 print(df.duplicated().sum()) # 查看具体是哪些行重复了 duplicate_rows df[df.duplicated(keepFalse)] # keepFalse标记所有重复项 print(duplicate_rows) # 基于特定列判断重复例如‘订单ID’应该唯一 print(df.duplicated(subset[订单ID]).sum()) # 删除重复行默认保留第一次出现的行 df_deduped df.drop_duplicates() # 删除重复行保留最后一次出现的行 df_deduped_last df.drop_duplicates(keeplast) # 基于‘订单ID’删除重复保留第一个 df_deduped_id df.drop_duplicates(subset[订单ID])3.3 数据类型转换给数据“上户口”错误的数据类型会导致计算错误或性能下降。最常见的是该是数字的列被识别为object文本。# 查看各列数据类型 print(df.dtypes) # 转换单列数据类型 df[销售额] pd.to_numeric(df[销售额], errorscoerce) # 将字符串转为数字无效的转为NaN df[日期] pd.to_datetime(df[日期], errorscoerce) # 转为日期时间类型 df[类别] df[类别].astype(category) # 转为分类类型节省内存加速分组 # 转换多列数据类型 df df.astype({列A: int32, 列B: float64}) # 批量转换将所有‘object’类型的列尝试转为字符串更节省内存的string类型如果pandas版本支持 for col in df.select_dtypes(include[object]).columns: df[col] df[col].astype(string)关于errors’coerce’这是一个非常重要的安全阀。当转换过程遇到无法解析的值如把“abc”转成数字时它会将其设置为NaN而不是直接抛出错误导致程序中断。这让你有机会后续检查这些异常值。3.4 字符串处理与列操作数据整形术数据经常需要拆分、合并、提取。# 示例数据df有一列‘姓名_部门’格式如‘张三_技术部’ df[姓名_部门].str.split(_, expandTrue) # 拆分expandTrue返回DataFrame df[[姓名’ ‘部门’]] df[‘姓名_部门’].str.split(‘_’ expandTrue) # 直接拆分成新列 # 字符串替换与清洗 df[‘地址’] df[‘地址’].str.replace(‘市’ ‘’).str.strip() # 去掉‘市’字并去除首尾空格 df[‘电话’] df[‘电话’].str.extract(r’(\d{11})’) # 用正则表达式提取11位手机号 # 创建新列派生列 df[‘销售额_万元’] df[‘销售额’] / 10000 df[‘是否达标’] df[‘销售额’] 10000 # 生成布尔列 df[‘利润率’] (df[‘利润’] / df[‘销售额’]).round(4) # 计算并保留4位小数 # 重命名列 df df.rename(columns{‘old_name’: ‘new_name’ ‘销售额’: ‘sales’}) # 删除列 df df.drop(columns[‘无用列1’ ‘无用列2’])4. 数据筛选、排序与分组聚焦你的分析目标清洗完的数据终于可以开始分析了。核心操作就是找到你要的数据按你的逻辑排序然后分组聚合。4.1 数据筛选如何快速“捞”出你要的数据筛选是数据分析中最频繁的操作。pandas提供了极其灵活和强大的布尔索引。1基于条件的行筛选# 单条件筛选销售额大于10000的记录 high_sales df[df[‘销售额’] 10000] # 多条件“与”and筛选销售额大于10000且来自‘北京’的记录 condition (df[‘销售额’] 10000) (df[‘城市’] ‘北京’) high_sales_bj df[condition] # 多条件“或”or筛选销售额大于10000或来自‘上海’的记录 condition (df[‘销售额’] 10000) | (df[‘城市’] ‘上海’) target_sales df[condition] # 条件“非”not筛选城市不是‘北京’和‘上海’的记录 condition ~df[‘城市’].isin([‘北京’ ‘上海’]) other_cities df[condition] # 字符串模糊筛选产品名称包含‘手机’的记录 condition df[‘产品名称’].str.contains(‘手机’ naFalse) # naFalse处理NaN值 phone_products df[condition]2基于列名的列筛选# 选择特定列 subset df[[‘日期’ ‘销售额’ ‘产品’]] # 选择列名符合某种模式的列需配合列表推导式 cols_start_with_s [col for col in df.columns if col.startswith(‘s’)] df_s df[cols_start_with_s]3.loc和.iloc精准定位的“手术刀”.loc基于标签label即索引名和列名进行筛选.iloc基于整数位置integer location进行筛选。# .loc 用法先行后列支持切片和布尔索引 df.loc[0 ‘销售额’] # 获取索引为0的行列名为‘销售额’的单个值 df.loc[0:5 [‘日期’ ‘销售额’]] # 获取索引0到5的行以及‘日期’和‘销售额’两列注意切片末端包含 df.loc[df[‘城市’] ‘北京’ ‘销售额’] # 获取所有城市为北京的行的‘销售额’列 # .iloc 用法基于整数位置 df.iloc[0 1] # 获取第0行第1列的值从0开始计数 df.iloc[0:5 0:2] # 获取前5行前2列切片末端不包含与Python列表一致4.2 数据排序让数据“井然有序”排序能帮你快速找到头部和尾部数据。# 按单列排序默认升序 df_sorted df.sort_values(‘销售额’) # 按单列降序排序 df_sorted_desc df.sort_values(‘销售额’ ascendingFalse) # 按多列排序先按‘城市’升序城市相同的再按‘销售额’降序 df_sorted_multi df.sort_values([‘城市’ ‘销售额’] ascending[True False]) # 按索引排序 df_sorted_index df.sort_index()4.3 数据分组与聚合洞察的“显微镜”分组聚合是数据分析的灵魂。它回答的是“每个X的Y是多少”这类问题比如“每个城市的平均销售额是多少”、“每个月的销售总额是多少”。1基础分组聚合# 按‘城市’分组计算‘销售额’的平均值 city_sales_mean df.groupby(‘城市’)[‘销售额’].mean() # 按‘城市’和‘产品’分组计算‘销售额’的总和与‘利润’的平均值 grouped df.groupby([‘城市’ ‘产品’]).agg({‘销售额’: ‘sum’ ‘利润’: ‘mean’}) print(grouped)groupby之后接aggaggregate的缩写是最常用的模式。agg里可以传入一个字典指定对哪些列进行哪些聚合运算。常见的聚合函数有sum,mean,median,min,max,count,std标准差,var方差等。2重置索引让分组结果更友好上面grouped的结果是一个多层索引的Series或DataFrame。有时我们希望把分组键‘城市’‘产品’变回普通的列。grouped_reset grouped.reset_index()3分组后应用复杂函数agg处理简单聚合apply则可以应用任意自定义函数。# 计算每个城市销售额的变异系数标准差/均值 def coefficient_of_variation(x): return x.std() / x.mean() cv_by_city df.groupby(‘城市’)[‘销售额’].apply(coefficient_of_variation)4分组筛选groupbyfilter# 筛选出至少有过3条销售记录的城市 df_filtered df.groupby(‘城市’).filter(lambda x: len(x) 3)一个实战心得分组聚合的结果经常需要进一步处理或可视化。我习惯在分组后立即reset_index()这样得到一个“干净”的DataFrame后续用matplotlib或seaborn画图时会非常方便不需要再处理多层索引。5. 数据合并与连接像拼图一样组合数据现实中的数据往往分散在多个表里。pandas提供了类似SQL的join操作来合并它们。5.1 纵向合并pd.concat用于将结构相同列名相同的多个DataFrame上下堆叠在一起。# 假设df1 df2 df3结构相同 df_combined pd.concat([df1 df2 df3] ignore_indexTrue)ignore_indexTrue会重置合并后的索引否则会保留原来的索引可能导致重复。5.2 横向连接pd.merge用于基于一个或多个键key将不同的DataFrame连接起来这是最像SQLJOIN的操作。# 假设df_orders有‘订单ID’‘客户ID’‘金额’ # df_customers有‘客户ID’‘客户名’‘城市’ # 内连接inner join只保留两个表都有的‘客户ID’ df_inner pd.merge(df_orders df_customers on‘客户ID’ how‘inner’) # 左连接left join以左表df_orders为准保留所有订单没有客户信息的填NaN df_left pd.merge(df_orders df_customers on‘客户ID’ how‘left’) # 右连接right join以右表df_customers为准 df_right pd.merge(df_orders df_customers on‘客户ID’ how‘right’) # 外连接outer join保留所有记录没有对应关系的填NaN df_outer pd.merge(df_orders df_customers on‘客户ID’ how‘outer’) # 基于多个键连接 df_complex pd.merge(df1 df2 on[‘年份’ ‘月份’] how‘inner’) # 左右表连接键列名不同时 df_diff_key pd.merge(df_orders df_customers left_on‘order_cust_id’ right_on‘cust_id’ how‘inner’)连接操作的核心参数on用于连接的列名。必须在两个DataFrame中都存在。how连接方式。innerleftrightouter。最常用的是left因为它能保证左表通常是你的主事实表如订单表的记录不丢失。suffixes当两个表有同名列但不是连接键时用于区分这些列的后缀。例如suffixes(‘_订单’ ‘_客户’)。5.3 一个常见的合并陷阱与排查合并后数据变多或变少了首先检查重复键和连接类型。# 检查左表的连接键是否有重复 print(df_orders[‘客户ID’].duplicated().sum()) # 检查右表的连接键是否有重复 print(df_customers[‘客户ID’].duplicated().sum())如果连接键有重复进行many-to-many连接会导致数据行数爆炸式增长笛卡尔积。这时你需要先对数据进行去重或聚合确保连接键唯一或者明确这就是你想要的many-to-many关系。6. 时间序列数据处理与时间做朋友很多业务数据都与时间相关。pandas对时间序列的支持是其一大杀手锏。6.1 时间类型转换与属性提取# 确保‘日期’列是datetime类型 df[‘日期’] pd.to_datetime(df[‘日期’]) # 提取时间分量 df[‘年份’] df[‘日期’].dt.year df[‘月份’] df[‘日期’].dt.month df[‘季度’] df[‘日期’].dt.quarter df[‘星期几’] df[‘日期’].dt.dayofweek # 周一0 周日6 df[‘是否周末’] df[‘日期’].dt.dayofweek 5 df[‘月初’] df[‘日期’].dt.to_period(‘M’).dt.to_timestamp() # 转换为当月第一天6.2 重采样与滚动窗口计算这是时间序列分析的核心用于将高频数据聚合为低频如日数据变月数据或计算移动平均等指标。# 假设df已按‘日期’排序且‘日期’是索引如果不是先用df.set_index(‘日期’ inplaceTrue)设置 df df.set_index(‘日期’) # 按周重采样计算每周销售额总和 weekly_sales df[‘销售额’].resample(‘W’).sum() # ‘W’表示周 ‘M’表示月 ‘Q’表示季 ‘Y’表示年 # 按月重采样计算每月销售额均值和订单数 monthly_stats df.resample(‘M’).agg({‘销售额’: ‘mean’ ‘订单ID’: ‘count’}) # 计算7天滚动平均销售额用于平滑曲线观察趋势 df[‘销售额_7d_avg’] df[‘销售额’].rolling(window7).mean() # 计算过去30天的累计销售额 df[‘销售额_30d_sum’] df[‘销售额’].rolling(window30).sum()关于rolling的min_periods参数默认情况下窗口需要被完全填满比如7天窗口需要前6个数据点才开始计算。这会导致结果的前几个值为NaN。如果你希望只要有数据就开始算可以设置min_periods1。df[‘销售额_7d_avg’] df[‘销售额’].rolling(window7 min_periods1).mean()7. 高效迭代与性能优化当数据量变大时虽然pandas的向量化操作已经非常高效应尽量避免显式循环如for row in df.iterrows()但在某些复杂逻辑下我们仍需要考虑迭代。这里有一些更优的选择。7.1 避免iterrows() 使用itertuples()iterrows()返回的是(index Series)对生成Series对象有开销很慢。itertuples()返回命名元组速度快得多。# 慢不推荐用于大数据集 for index row in df.iterrows(): # 用row[‘列名’]访问数据 # 快推荐 for row in df.itertuples(): # 用row.列名 访问数据 例如 row.销售额 # 索引可以通过row.Index访问7.2 终极武器apply与向量化apply方法可以将一个函数应用到DataFrame的某一轴行或列上它底层是Cython优化过的通常比Python层级的循环快。# 对每一行应用一个函数创建新列 def calculate_profit_margin(row): if row[‘销售额’] 0: return row[‘利润’] / row[‘销售额’] else: return 0 df[‘利润率’] df.apply(calculate_profit_margin axis1) # axis1 表示按行 # 对某一列应用函数 df[‘城市_缩写’] df[‘城市’].apply(lambda x: x[:2]) # 取城市名前两个字但是apply也不是万能的。如果可能尽量使用pandas内置的向量化函数如.str方法 算术运算它们的速度是最快的。# 向量化操作速度最快首选 df[‘利润率’] df[‘利润’] / df[‘销售额’] df[‘利润率’] df[‘利润率’].where(df[‘销售额’] 0 0) # 处理除零情况 # 使用np.where进行条件向量化赋值 import numpy as np df[‘等级’] np.where(df[‘销售额’] 10000 ‘高’ ‘低’)7.3 处理大数据集的技巧分块与数据类型优化当数据文件大到内存无法一次性加载时# 分块读取CSV chunk_size 100000 # 每次读10万行 chunks [] for chunk in pd.read_csv(‘huge_data.csv’ chunksizechunk_size): # 对每个chunk进行必要的处理 processed_chunk do_some_processing(chunk) chunks.append(processed_chunk) # 最后将所有处理好的块合并 df_processed pd.concat(chunks ignore_indexTrue)优化数据类型以节省内存# 查看内存使用 print(df.info(memory_usage‘deep’)) # 将数值列从int64/float64向下转换 df[‘小整数列’] df[‘小整数列’].astype(‘int32’) df[‘小数列’] df[‘小数列’].astype(‘float32’) # 将文本列从object转为category如果唯一值较少 if df[‘城市’].nunique() / len(df) 0.5: # 唯一值比例小于50% df[‘城市’] df[‘城市’].astype(‘category’)8. 实战案例串联一个简单的销售数据分析流程让我们把上面的代码片段串起来模拟一个从数据加载到产出洞察的简单流程。假设我们有一个sales_data.csv文件包含date日期city城市product产品sales销售额profit利润字段。import pandas as pd import numpy as np # 1. 加载与探查 print(“步骤1: 加载数据...”) df pd.read_csv(‘sales_data.csv’ encoding‘utf-8-sig’) print(“数据形状:” df.shape) print(“\n数据预览:”) print(df.head()) print(“\n数据信息:”) print(df.info()) print(“\n描述性统计:”) print(df.describe()) # 2. 数据清洗 print(“\n步骤2: 数据清洗...”) # 检查缺失 print(“缺失值统计:”) print(df.isnull().sum()) # 假设我们决定用0填充利润的缺失值删除销售额缺失的行 df[‘profit’].fillna(0 inplaceTrue) df.dropna(subset[‘sales’] inplaceTrue) # 处理日期 df[‘date’] pd.to_datetime(df[‘date’]) df[‘year’] df[‘date’].dt.year df[‘month’] df[‘date’].dt.month df[‘quarter’] df[‘date’].dt.quarter # 3. 核心分析 print(“\n步骤3: 核心分析...”) # 按城市和产品分析销售额和利润 city_product_analysis df.groupby([‘city’ ‘product’]).agg({ ‘sales’: [‘sum’ ‘mean’ ‘count’] ‘profit’: ‘sum’ }).round(2) city_product_analysis.columns [‘销售额_总和’ ‘销售额_均值’ ‘订单数’ ‘利润_总和’] # 扁平化列名 print(“按城市和产品分析:”) print(city_product_analysis.head(10)) # 计算整体利润率 df[‘profit_margin’] (df[‘profit’] / df[‘sales’]).replace([np.inf -np.inf] np.nan).fillna(0) overall_margin df[‘profit_margin’].mean() print(f”\n整体平均利润率: {overall_margin:.2%}“) # 月度趋势分析 monthly_trend df.set_index(‘date’).resample(‘M’)[‘sales’].sum() print(“\n月度销售额趋势:”) print(monthly_trend.head()) # 4. 输出结果 print(“\n步骤4: 保存结果...”) # 保存清洗后的数据 df.to_csv(‘cleaned_sales_data.csv’ indexFalse encoding‘utf-8-sig’) # 保存分析报告 city_product_analysis.to_excel(‘sales_analysis_report.xlsx’ sheet_name‘城市产品分析’) print(“分析完成结果已保存。”)这个流程覆盖了读取、清洗、转换、分组聚合、时间序列分析和结果输出的完整链条。你可以根据自己数据的实际情况调整其中的每一步。记住pandas是一个工具库真正的魔法在于你如何组合这些基础操作来解决具体的业务问题。多练多踩坑你很快就能得心应手。
返回列表