Pandas数据分析全流程——从数据导入到结果输出,这一篇文章就够了 🚀

文章比较干,请备好水再看

今天,咱们不讲大道理,直接来点实战------教大家如何从0到1搞定Pandas数据分析的全流程!开干,咱玩的就是真实!


1. 数据导入------把"脏数据"请进来

首先得把数据请进来。数据来源可能是CSV、Excel,甚至数据库。这里咱们就直接模拟生成一份数据,数据里面充满了各种"坑":

python 复制代码
import pandas as pd
import numpy as np

# 模拟生成数据(注意:这里故意加了缺失值、异常值、重复数据以及格式混乱的日期)
data = {
    "姓名": ["张三", "李四", "王五", "赵六", "小明", "小红", "老王", "张三", "赵六"],
    "年龄": [25, 30, 22, np.nan, 29, 26, 28, 25, 200],  # 缺失值 & 异常值
    "工龄": [2, 5, 1, 8, np.nan, 3, -1, 2, 10],          # 缺失值 & 错误数据(负数)
    "薪资": [8000, 12000, 6000, 15000, 10000, 9000, 8500, 8000, 16000],  # 重复行
    "入职日期": ["2022-06-01", "2020/05/15", "2021-09-10", "2019-12-01", 
               "2023/01/01", "2021-08-15", "2018-03-10", "2022-06-01", "2019-12-01"],  # 日期格式混乱
    "部门": ["市场部", "技术部", "市场部", "技术部", "市场部", "人事部", "技术部", "市场部", "财务部"]
}

df = pd.DataFrame(data)
print("导入数据:\n", df)

以下帮大家简单给出几个读取Excel、csv、数据库的示例代码,方便新手也能快速上手:

读取CSV文件

python 复制代码
import pandas as pd

# 读取CSV文件(确保data.csv文件在当前目录下)
df_csv = pd.read_csv('data.csv')
print("CSV数据预览:")
print(df_csv.head())

说明pd.read_csv() 非常好用,直接加载CSV数据。记得检查文件路径哦~


读取Excel文件

python 复制代码
import pandas as pd

# 读取Excel文件的第一个工作表
df_excel = pd.read_excel('data.xlsx', sheet_name='Sheet1')
print("Excel数据预览:")
print(df_excel.head())

说明pd.read_excel() 可以指定工作表名(或索引)。


从数据库读取数据

这里用SQLAlchemy作为数据库引擎示例,假设你使用的是SQLite数据库(其他数据库类似,只需更换连接字符串)。

python 复制代码
import pandas as pd
from sqlalchemy import create_engine

# 创建数据库引擎(这里使用SQLite数据库,数据库文件为mydatabase.db)
engine = create_engine('sqlite:///mydatabase.db')

# 编写SQL查询语句
query = "SELECT * FROM table_name"

# 读取数据库中的数据
df_db = pd.read_sql(query, engine)
print("数据库数据预览:")
print(df_db.head())

说明pd.read_sql() 可以直接执行SQL语句,将查询结果转成DataFrame,超方便!💡


2. 数据清洗🛁

数据清洗其实就是对症下药,让数据变得干净、标准,便于后续处理。这里主要包括:

2.1 缺失值处理

首先看看哪些地方数据"不完整":

python 复制代码
print("缺失值统计:\n", df.isnull().sum())
go 复制代码
缺失值统计:
姓名      0
年龄      1
工龄      1
薪资      0
入职日期   0
部门      0
dtype: int64

通过缺失值统计可以发现年龄和工龄2列分别有1个缺失值。

处理策略:

  • 年龄 缺失值用中位数填充(受极端值影响小)
  • 工龄 缺失值用部门内均值补全(让每个部门的数据更有说服力)
python 复制代码
df["年龄"]=df["年龄"].fillna(df["年龄"].median())
df["工龄"]=df["工龄"].fillna(df.groupby("部门")["工龄"].transform("mean"))

我们可以看到赵六 缺失的年龄和小明缺失的工龄已经按照处理策略进行了填充。


实际数据分析中,缺失值(NaN)是最常见的问题。处理方式一般取决于业务需求和数据特点。以下是常见的缺失值处理策略,以及适用场景:

🌟 2.1.1 删除缺失值

适用于:

  • 缺失值占比极少(比如 < 5%)
  • 该列不是关键数据
  • 业务可以接受少量数据丢失

示例:

python 复制代码
import pandas as pd

df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', None, '赵六'],
    '年龄': [23, 25, None, 30, 28],
    '薪资': [5000, 7000, None, 8000, 9000]
})

df_dropna = df.dropna()  # 删除含缺失值的行
print(df_dropna)

变体:

  • df.dropna(subset=['某列']) 只删除特定列缺失的行
  • df.dropna(axis=1) 删除含缺失值的列(谨慎使用)

💡 2.1.2 用特定值填充

适用于:

  • 缺失值占比较高,但可以用默认值替代
  • 比如:填充 0(财务数据)、填充 "未知"(分类数据)

示例:

python 复制代码
df_filled = df.fillna({'姓名': '未知', '年龄': df['年龄'].mean(), '薪资': 0})
print(df_filled)

解释:

  • df.fillna(value) 可用于填充缺失值
  • df['某列'].mean() 用该列均值填充(适用于数值数据)
  • df['某列'].median() 用中位数填充,适用于受极端值影响的数据
  • df['某列'].mode()[0] 用众数填充(适用于分类变量)

🔁 2.1.3 插值填充

适用于:

  • 时间序列数据,可以用前后数据预测缺失值

示例:

python 复制代码
df_interpolated = df.interpolate()
print(df_interpolated)

解释:

  • interpolate() 采用线性插值法填充数值缺失值(适用于趋势平稳的数据)

📊 2.1.4 前向/后向填充

适用于:

  • 时间序列数据,如股票价格、天气数据等

示例:

python 复制代码
df_ffill = df.ffill() # 前向填充(用前一行数据填充)
df_bfill = df.bfill()  # 后向填充(用后一行数据填充)

⚠️ 注意

  • 适用于有逻辑顺序的数据(如日期、时间)
  • 如果缺失值连续过多,效果可能不佳

🎯 2.1.5 机器学习模型预测填充

适用于:

  • 缺失值较多且无法简单填充
  • 需要更精确地估计缺失值,如回归预测缺失数值、分类模型预测缺失类别

示例(简单回归填充):

python 复制代码
from sklearn.impute import SimpleImputer
import numpy as np

imputer = SimpleImputer(strategy='mean')  # 也可以换成 'median' 或 'most_frequent'
df['年龄'] = imputer.fit_transform(df[['年龄']])

高级方法:

  • 使用 KNNImputer(基于最近邻填充)
  • RandomForestRegressorXGBoost 预测缺失值

总之一切要根据业务场景来处理,拒绝🙅无脑 fillna(0)


2.2 异常值处理

异常值处理也是数据分析中最常见的场景了。比如200岁的"长生不老者"或负数工龄:

python 复制代码
# 年龄异常值处理:用箱线图法(IQR)检测并剔除异常值
Q1 = df["年龄"].quantile(0.25)
Q3 = df["年龄"].quantile(0.75)
IQR = Q3 - Q1
df = df[(df["年龄"] >= Q1 - 1.5 * IQR) & (df["年龄"] <= Q3 + 1.5 * IQR)]
# 工龄负数也不合理,直接过滤
df = df[df["工龄"] >= 0]

在实际工作中,处理异常值的方式取决于业务需求、数据类型和分析目标。以下是常见的异常值处理策略,每种方法都附带 适用场景 !🎯

🔍 2.2.1 直接删除异常值

适用于:

  • 异常值是明显的错误数据,例如年龄 = 200、工资 = -5000
  • 异常值数量较少,删除不会影响整体分析

示例:(删除年龄超过 100 岁的异常数据)

python 复制代码
import pandas as pd

df = pd.DataFrame({'姓名': ['张三', '李四', '王五', '赵六'], '年龄': [25, 30, 150, 28]})

df_filtered = df[df['年龄'] < 100]  # 只保留年龄小于100的数据
print(df_filtered)

变体

  • df.drop(df[df['某列'] > 阈值].index, inplace=True)
    适用于多个条件删除

📊 2.2.2 用统计方法识别异常值

📌 方法 1:基于均值和标准差(3σ 法则)

适用于:

  • 数据服从正态分布
  • 适用于数值型数据,如薪资、身高、体重

原理:

如果数据服从正态分布,99.7% 的数据应该在 均值 ± 3*标准差 之间,超出范围的可以认为是异常值。

python 复制代码
import numpy as np

# 生成示例数据
df = pd.DataFrame({'工资': [5000, 5500, 7000, 9000, 20000]})

mean = df['工资'].mean()
std = df['工资'].std()

# 3σ 规则
df_filtered = df[(df['工资'] > mean - 3 * std) & (df['工资'] < mean + 3 * std)]
print(df_filtered)

⚠️ 注意

  • 该方法适用于正态分布数据,但如果数据偏态(如工资通常是右偏的),就不适用了。

📌 方法 2:基于 IQR(四分位数法) 适用于:

  • 数据不一定服从正态分布
  • 适用于房价、工龄等非对称数据

原理:

IQR(四分位距)= Q3(75% 分位数)- Q1(25% 分位数),通常认为超出1.5 倍 IQR 的数据是异常值。

python 复制代码
# 计算四分位数
Q1 = df['工资'].quantile(0.25)  # 下四分位数
Q3 = df['工资'].quantile(0.75)  # 上四分位数
IQR = Q3 - Q1  # 四分位距

# 计算异常值范围
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 过滤掉异常值
df_filtered = df[(df['工资'] >= lower_bound) & (df['工资'] <= upper_bound)]
print(df_filtered)

优点 :适用于偏态数据,不受极端值影响。

⚠️ 缺点:如果数据本身就有很大波动,可能会误删正常数据。


🔄 2.2.3 替换异常值

适用于:

  • 异常值较多,不宜直接删除
  • 业务允许用合适的统计值替换异常值
(1)用均值/中位数替换
python 复制代码
median = df['工资'].median()
df.loc[df['工资'] > upper_bound, '工资'] = median
df.loc[df['工资'] < lower_bound, '工资'] = median

💡 适用于:异常值较少,且数据对极端值不敏感时。

(2)用前一个或后一个值填充

适用于:

  • 时间序列数据(如股票价格、气温等)
  • 异常值是偶然波动造成的
python 复制代码
df['工资'] = df['工资'].replace(df['工资'][df['工资'] > upper_bound], method='ffill')  # 用前一个值填充

📈 2.2.4 使用机器学习模型检测异常值

适用于:

  • 数据分布复杂,难以手动设置阈值
  • 对异常值检测要求高
(1)使用 Isolation Forest 识别异常值
python 复制代码
from sklearn.ensemble import IsolationForest

model = IsolationForest(contamination=0.05)  # 设定异常值比例 5%
df['is_outlier'] = model.fit_predict(df[['工资']])

# 过滤掉异常值
df_filtered = df[df['is_outlier'] == 1]
print(df_filtered)

💡 适用于:高维数据、非线性数据,如信用卡欺诈检测。


🚀 2.2.5 分箱处理异常值

适用于:

  • 异常值是业务逻辑上的"极端值"
  • 比如年龄 80 岁以上算"高龄",可以归类到"老年"
python 复制代码
df['工资等级'] = pd.cut(df['工资'], bins=[0, 5000, 10000, 20000], labels=['低', '中', '高'])
print(df)

💡 适用于:工资、年龄、分数等有固定区间的数据。


2.3 重复值处理

重复数据?老板说数据要"一丝不苟",咱们就把重复的记录给"去水分"了:

python 复制代码
df.drop_duplicates(inplace=True)

当然在实际工作中,重复数据不能上来就给老板删掉,还是要结合业务场景。以下是常见的重复值处理策略!

🔍 2.3.1 检查数据中是否存在重复值

在处理之前,先检查是否有重复值

python 复制代码
import pandas as pd

df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '张三', '赵六'],
    '年龄': [25, 30, 35, 25, 28],
    '薪资': [5000, 7000, 9000, 5000, 8000]
})

# 检查数据是否存在重复值
print(df.duplicated())  # 返回布尔值,每行为 True 表示该行是重复的
print(df.duplicated().sum())  # 统计重复行的个数

df.duplicated() 默认检查整行是否完全相同


🗑️ 2.3.2 删除重复值

适用于:

  • 重复数据是明显的错误数据
  • 不会影响业务逻辑
python 复制代码
df_no_duplicates = df.drop_duplicates()
print(df_no_duplicates)

⚠️ 注意

  • drop_duplicates() 默认删除完全重复的行,保留第一条
  • drop_duplicates(keep='last') 保留最后一条
  • drop_duplicates(keep=False) 删除所有重复项
🎯 只针对某几列去重

如果某些列重复,而其他列不重要,可以指定列去重:

python 复制代码
df_no_duplicates = df.drop_duplicates(subset=['姓名'])

💡 适用于: 去重时只关心某些关键字段,比如手机号、订单号等。


📊 2.3.3 标记重复值而不删除

适用于:

  • 想要保留重复数据,但标记出来方便分析
python 复制代码
df['是否重复'] = df.duplicated()
df['是否重复_保留第一条'] = df.duplicated(keep='first')
df['是否重复_保留最后一条'] = df.duplicated(keep='last')

print(df)

适用于数据质量检查,可以筛选出来进一步分析。


🔄 2.3.4 合并重复数据

适用于:

  • 同一个实体存在多条记录,但信息不完整
  • 希望合并信息,而不是简单删除
(1)使用 groupby 合并
python 复制代码
df_grouped = df.groupby('姓名', as_index=False).agg({
    '年龄': 'first',  # 取第一条记录的年龄
    '薪资': 'mean'    # 计算平均薪资
})
print(df_grouped)

💡 适用于:

  • 客户信息合并(如同一个手机号多次注册)
  • 订单数据合并(如同一客户多次购买)
(2)用 fillna() 合并缺失值

如果多条重复数据中某些字段为空,可以合并补全:

python 复制代码
df_filled = df.groupby('姓名', as_index=False).first()  # 保留第一条完整数据
print(df_filled)

适用于补全客户、产品信息等场景


🎭 2.3.5 处理轻微重复(模糊去重)

适用于:

  • 数据不完全相同,但本质是同一个实体
  • 比如姓名错别字、邮箱格式不同等
(1)去掉首尾空格
python 复制代码
df['姓名'] = df['姓名'].str.strip()
(2)大小写统一
python 复制代码
df['姓名'] = df['姓名'].str.lower()
(3)模糊匹配去重(fuzzywuzzy

适用于:

  • 姓名、公司名称等可能有轻微差异
python 复制代码
from fuzzywuzzy import process

name_list = df['姓名'].tolist()
match = process.extract('张三', name_list, limit=3)  # 找到最相似的3个名字
print(match)

适用于客户数据、企业名称等可能存在拼写差异的场景

2.4 日期格式统一

日期格式乱七八糟?别慌,Pandas自带神仙函数来拯救:

python 复制代码
# 适用于日期分隔符不同的情况(/、-、.)
df['入职日期'] = df['入职日期'].str.replace(r'[/.-]', '-', regex=True)  # 统一为 "YYYY-MM-DD"
df['入职日期'] = pd.to_datetime(df['入职日期'], errors='coerce')  # 解析日期

到这一步,数据清理就搞定了!


3. 数据处理与转换------给数据穿上漂亮的"外衣"

数据清洗完后,我们常常需要对数据进行一些转换,方便后续分析。比如对数值型数据进行归一化、对类别数据进行编码,或创建一些新的特征。

3.1 数据类型转换

确保每列数据都是你预期的类型,这样在做数值计算和统计时才不会出岔子:

python 复制代码
df["年龄"] = df["年龄"].astype(int)
df["工龄"] = df["工龄"].astype(int)

3.2 新特征生成

有时候你会想知道每个人的"经验指数",简单来说就是工龄与年龄的比值,顺便让数据更有看头:

python 复制代码
df["经验指数"] = df["工龄"] / df["年龄"]

这样,数据不仅干净,还穿上了漂亮的新装,等待你去探索!


4. 数据探索与分析------让数据自己"说话" 📊

这一步可是重头戏!数据探索需要结合统计方法和业务背景,找出数据背后的秘密。作为专业人士,我们要做到以下几点:

4.1 描述性统计

通过基本统计量了解数据的分布和趋势:

python 复制代码
print("数据描述性统计:\n", df.describe())

4.2 部门薪资分析

分析不同部门的薪资分布,不仅能看出部门间的差距,也能发现数据中的潜在问题,比如是否存在薪资异常或数据偏态现象。

python 复制代码
# 按部门统计平均薪资和薪资中位数
dept_salary_stats = df.groupby("部门")["薪资"].agg(["mean", "median"])
print("各部门薪资统计:\n", dept_salary_stats)

专业点拨

  • 均值受极端值影响较大,而中位数更稳健
  • 如果两者差距较大,可能暗示数据中存在异常值或偏态分布

4.3 工龄与薪资关系

探讨工龄对薪资的影响,利用散点图和回归分析帮助我们发现趋势:

python 复制代码
import seaborn as sns
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.figure(figsize=(8, 5))
sns.regplot(x="工龄", y="薪资", data=df, scatter_kws={"s": 50}, line_kws={"color": "red"})
plt.title("工龄与薪资的关系")
plt.xlabel("工龄")
plt.ylabel("薪资")
plt.show()

专业点拨

  • 观察散点图中数据点的分布,可以判断是否存在线性关系
  • 适当加入回归线可以帮助我们更直观地理解趋势和波动

4.4 经验指数解读

用"经验指数"来评估员工的成长与稳定性,这一指标能帮助HR判断哪些员工既有潜力又稳扎稳打:

python 复制代码
plt.figure(figsize=(8, 5))
sns.boxplot(x="部门", y="经验指数", data=df)
plt.title("各部门经验指数分布")
plt.xlabel("部门")
plt.ylabel("经验指数")
plt.show()

这一步,不仅是数据分析,更像是给数据做一次"全身检查",发现每个细节问题,让决策者有据可依!


5. 数据可视化------把分析结果变成"图说故事" 🎨

数据可视化能让我们的分析结果更直观,也更容易与非技术同事沟通。这里再展示几个常用的可视化手段:

5.1 部门薪资箱线图

直观展示不同部门薪资的分布及异常值:

python 复制代码
plt.figure(figsize=(8, 5))
sns.boxplot(x="部门", y="薪资", data=df)
plt.title("各部门薪资箱线图")
plt.xlabel("部门")
plt.ylabel("薪资")
plt.show()

5.2 平均薪资柱状图

用柱状图展示各部门平均薪资,让数据更"高大上":

python 复制代码
avg_salary = df.groupby("部门")["薪资"].mean().reset_index()
plt.figure(figsize=(8, 5))
sns.barplot(x="部门", y="薪资", data=avg_salary)
plt.title("各部门平均薪资")
plt.xlabel("部门")
plt.ylabel("平均薪资")
plt.show()

5.3 多变量关联图

综合展示工龄、薪资与部门之间的关系,适合对数据做多角度解读:

python 复制代码
plt.figure(figsize=(8, 5))
sns.scatterplot(x="工龄", y="薪资", hue="部门", size="经验指数", data=df, sizes=(50, 200))
plt.title("工龄、薪资及经验指数多变量关联图")
plt.xlabel("工龄")
plt.ylabel("薪资")
plt.show()

这些图表不仅让数据"活"起来,还能迅速传达关键信息,让数据决策不再枯燥。


6. 结果输出------把成果交给决策者 📤

分析完数据,最后一步就是输出结果,为业务决策提供支持。常见做法包括生成报告、保存清洗后的数据文件,或者构建交互式仪表盘。

6.1 输出清洗后的数据

python 复制代码
# 将处理后的数据保存为CSV文件,方便后续使用
df.to_csv("cleaned_data.csv", index=False)
print("清洗后的数据已保存!")

6.2 生成分析报告

把关键统计量、图表和结论整合到报告中,可以用Jupyter Notebook导出HTML,或者用其他BI工具制作仪表盘。这样,老板一看就能知道咱们做了哪些功课!


总结

🎉 今天我们从数据导入、清洗、处理与转换,到数据探索与专业分析,再到可视化和结果输出,走了一遍完整的Pandas数据分析全流程。

  • 数据清洗:补缺、剔除异常、去重复,让数据变得标准可靠
  • 数据处理与转换:类型转换、新特征生成,为深度分析打下基础
  • 数据探索与分析:用描述统计、分组对比和回归分析,找出数据背后的规律
  • 数据可视化:多种图表助力,让复杂数据变得一目了然
  • 结果输出:把成果整理成报告,给决策者一份专业的"数据药方"

顺手点赞 + 在看,就是对花姐最大的支持!

相关推荐
虽千万人 吾往矣6 分钟前
golang channel源码
开发语言·后端·golang
_十六17 分钟前
文档即产品!工程师必看的写作密码
前端·后端
radient18 分钟前
线上FullGC问题如何排查 - Java版
后端·架构
6confim22 分钟前
掌握 Cursor:AI 编程助手的高效使用技巧
前端·人工智能·后端
知其然亦知其所以然33 分钟前
面试官问我 Java 原子操作,我一句话差点让他闭麦!
java·后端·面试
Lx35234 分钟前
📌K8s生产环境排错之:那些暗黑操作
后端·kubernetes
栗筝i38 分钟前
Spring Boot 核心模块全解析:12 个模块详解及作用说明
java·spring boot·后端
Cache技术分享41 分钟前
55. Java 类和对象 - 了解什么是对象
java·后端
楽码43 分钟前
理解go指针和值传递
后端·go·编程语言