Pandas实战 DataFrame数据处理、清洗与统计分析全解析

Pandas是Python数据处理领域的核心库,而DataFrame作为其核心数据结构,是处理结构化数据的必备工具。本文从实际业务场景出发,详解DataFrame的基础操作、数据清洗核心方法和统计分析技巧,内容覆盖新手入门到实战应用,帮助你高效处理各类数据问题。

一、环境准备与DataFrame基础

1. 安装与导入

首先确保安装了Pandas库,建议搭配NumPy使用(数据计算更高效):

pip install pandas numpy

导入常用库:

import pandas as pd
import numpy as np

2. 创建DataFrame

DataFrame可理解为“带标签的二维表格”,支持从列表、字典、CSV/Excel文件等多种方式创建,以下是最常用的场景:

# 1. 从字典创建(最常用)
data = {
    "姓名": ["张三", "李四", "王五", "赵六"],
    "年龄": [25, 32, 28, np.nan],  # 包含缺失值
    "城市": ["北京", "上海", "广州", "北京"],
    "月薪": [8000, 12000, 9500, 15000]
}
df = pd.DataFrame(data)

# 2. 从CSV文件读取(实战核心)
# df = pd.read_csv("data.csv", encoding="utf-8")

# 3. 从Excel文件读取
# df = pd.read_excel("data.xlsx", sheet_name="Sheet1")

# 查看数据基本信息
print("数据前3行:")
print(df.head(3))  # 查看前n行,默认5行
print("\n数据维度:", df.shape)  # (行数, 列数)
print("\n数据类型:")
print(df.dtypes)
print("\n数据概览:")
print(df.info())  # 含非空值数量、数据类型等关键信息

3. 基础索引与筛选

快速定位和提取目标数据是DataFrame的基础能力,掌握以下操作可解决80%的基础筛选需求:

# 1. 按列名提取列
name_series = df["姓名"]  # 单列,返回Series
name_salary_df = df[["姓名", "月薪"]]  # 多列,返回DataFrame

# 2. 按行筛选(布尔索引)
# 筛选月薪大于10000的行
high_salary_df = df[df["月薪"] > 10000]
# 筛选北京地区且年龄小于30的行
beijing_young_df = df[(df["城市"] == "北京") & (df["年龄"] < 30)]

# 3. 按位置筛选(iloc)
first_row = df.iloc[0]  # 第一行
col_2_to_3 = df.iloc[:, 1:3]  # 第2-3列(所有行)

# 4. 按标签筛选(loc,需设置索引)
df_index = df.set_index("姓名")
li_salary = df_index.loc["李四", "月薪"]  # 李四的月薪

二、DataFrame数据清洗(实战核心)

真实数据往往存在缺失值、重复值、异常值,数据清洗是分析前的关键步骤,直接影响分析结果的准确性。

1. 缺失值处理

缺失值(NaN)是最常见的问题,需根据业务场景选择删除、填充或插值:

# 1. 查看缺失值
print("缺失值统计:")
print(df.isnull().sum())  # 按列统计缺失值数量

# 2. 删除缺失值(适用于缺失率低的情况)
df_drop = df.dropna()  # 删除所有含缺失值的行
# df_drop_col = df.dropna(axis=1)  # 删除含缺失值的列
# df_drop_thresh = df.dropna(thresh=3)  # 保留至少3个非空值的行

# 3. 填充缺失值(更常用)
df_fill = df.copy()
# 数值型列用均值填充
df_fill["年龄"] = df_fill["年龄"].fillna(df_fill["年龄"].mean())
# 分类列用众数填充
df_fill["城市"] = df_fill["城市"].fillna(df_fill["城市"].mode()[0])
# 用指定值填充
df_fill["月薪"] = df_fill["月薪"].fillna(0)

# 4. 插值填充(适用于时序数据)
# df_fill["年龄"] = df_fill["年龄"].interpolate()  # 线性插值

2. 重复值处理

重复数据会导致统计结果偏差,需先检测再删除:

# 1. 检测重复行
print("重复行数量:", df.duplicated().sum())
# 检测指定列的重复(如姓名+城市重复)
print("指定列重复数:", df.duplicated(subset=["姓名", "城市"]).sum())

# 2. 删除重复行
df_drop_dup = df.drop_duplicates()  # 删除完全重复的行
# 保留第一次出现的重复行(默认),保留最后一次用keep="last"
df_drop_dup_subset = df.drop_duplicates(subset=["姓名"], keep="first")

3. 异常值处理

异常值(如月薪为负数、年龄超过100)需识别并处理,常用方法为箱线图检测或3σ原则:

# 方法1:箱线图检测(可视化)
import matplotlib.pyplot as plt
plt.boxplot(df["月薪"])
plt.title("月薪箱线图(识别异常值)")
plt.show()

# 方法2:3σ原则(适用于正态分布数据)
def remove_outliers(df, col):
    mean = df[col].mean()
    std = df[col].std()
    # 筛选在3个标准差内的数据
    df_clean = df[(df[col] > mean - 3*std) & (df[col] < mean + 3*std)]
    return df_clean

df_salary_clean = remove_outliers(df, "月薪")

# 方法3:替换异常值(用中位数)
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["月薪"] = np.where(
    (df["月薪"] < lower_bound) | (df["月薪"] > upper_bound),
    df["月薪"].median(),
    df["月薪"]
)

4. 数据格式与类型清洗

# 1. 列类型转换
df["年龄"] = df["年龄"].astype("float64")  # 转为浮点型
df["月薪"] = df["月薪"].astype("int64")  # 转为整型
df["入职时间"] = pd.to_datetime(df["入职时间"], format="%Y-%m-%d")  # 转为日期型

# 2. 字符串清洗(如城市列去空格、统一大小写)
df["城市"] = df["城市"].str.strip()  # 去除首尾空格
df["城市"] = df["城市"].str.replace("北京市", "北京")  # 替换字符
df["姓名"] = df["姓名"].str.upper()  # 转为大写

# 3. 列名规范化
df.rename(columns={"姓名": "name", "年龄": "age"}, inplace=True)  # 重命名列
df.columns = df.columns.str.lower()  # 列名转为小写

三、DataFrame统计分析(业务实战)

数据清洗完成后,可通过统计分析挖掘数据价值,以下是最常用的分析方法。

1. 基础描述性统计

快速获取数据的集中趋势、离散程度等核心指标:

# 整体描述统计(仅数值型列)
print("基础统计指标:")
print(df.describe())

# 单独统计指标
print("月薪均值:", df["月薪"].mean())
print("年龄中位数:", df["年龄"].median())
print("城市众数:", df["城市"].mode()[0])
print("月薪标准差:", df["月薪"].std())
print("月薪最大值/最小值:", df["月薪"].max(), "/", df["月薪"].min())
print("月薪分位数:", df["月薪"].quantile([0.25, 0.5, 0.75]))

# 分类列统计
print("各城市人数:")
print(df["城市"].value_counts())  # 计数
print("各城市占比:")
print(df["城市"].value_counts(normalize=True) * 100)  # 占比(百分比)

2. 分组统计(groupby)

按分类字段聚合分析,是业务分析的核心操作:

# 按城市分组,统计月薪的均值、总和、数量
city_salary = df.groupby("城市")["月薪"].agg(["mean", "sum", "count"])
print("各城市月薪统计:")
print(city_salary)

# 多字段分组+多指标聚合
city_age_salary = df.groupby(["城市", "年龄"])["月薪"].agg({
    "月薪均值": "mean",
    "月薪最大值": "max",
    "人数": "count"
}).reset_index()
print("各城市各年龄段月薪统计:")
print(city_age_salary)

# 分组后筛选(如筛选人数大于1的城市)
city_filter = df.groupby("城市").filter(lambda x: len(x) > 1)

3. 透视表与交叉表

透视表(pivot_table)是分组统计的可视化形式,交叉表(crosstab)适用于分类变量分析:

# 透视表:行=城市,列=年龄段,值=月薪,聚合方式=均值
df["年龄段"] = pd.cut(df["年龄"], bins=[20, 25, 30, 35], labels=["20-25", "25-30", "30-35"])
pivot_df = pd.pivot_table(
    df,
    values="月薪",
    index="城市",
    columns="年龄段",
    aggfunc="mean",
    fill_value=0  # 缺失值填充为0
)
print("各城市各年龄段月薪透视表:")
print(pivot_df)

# 交叉表:统计各城市各年龄段的人数
cross_df = pd.crosstab(df["城市"], df["年龄段"], margins=True)  # margins=True显示总计
print("各城市各年龄段人数交叉表:")
print(cross_df)

4. 相关性分析

分析数值型变量间的线性关系,常用皮尔逊相关系数:

# 计算相关性矩阵
corr_matrix = df[["年龄", "月薪"]].corr()
print("相关性矩阵:")
print(corr_matrix)

# 可视化相关性(热力图)
import seaborn as sns
sns.heatmap(corr_matrix, annot=True, cmap="coolwarm", fmt=".2f")
plt.title("年龄与月薪相关性热力图")
plt.show()

5. 数据排序与排名

# 按月薪降序排序
df_sorted = df.sort_values(by="月薪", ascending=False)

# 按城市升序、年龄降序排序
df_sorted_multi = df.sort_values(by=["城市", "年龄"], ascending=[True, False])

# 月薪排名(ascending=False表示降序,dense表示密集排名)
df["月薪排名"] = df["月薪"].rank(method="dense", ascending=False)

四、实战案例:员工薪资数据分析

结合以上知识点,完成一个完整的分析流程:

# 1. 读取数据
df = pd.read_csv("employee_salary.csv", encoding="utf-8")

# 2. 数据清洗
# 处理缺失值
df["年龄"] = df["年龄"].fillna(df["年龄"].median())
df["部门"] = df["部门"].fillna("未知")
# 删除重复行
df = df.drop_duplicates(subset=["员工编号"])
# 处理异常值(月薪小于0或大于10万为异常)
df.loc[(df["月薪"] < 0) | (df["月薪"] > 100000), "月薪"] = df["月薪"].median()

# 3. 统计分析
# 各部门薪资均值、中位数
dept_salary = df.groupby("部门")["月薪"].agg(["mean", "median"]).round(2)
print("各部门薪资统计:")
print(dept_salary)

# 各城市薪资TOP10
city_top10 = df.groupby("城市")["月薪"].nlargest(10).reset_index()
print("\n各城市薪资TOP10:")
print(city_top10)

# 年龄与月薪的相关性
corr = df[["年龄", "月薪"]].corr().iloc[0, 1].round(2)
print(f"\n年龄与月薪的相关系数:{corr}")

# 4. 结果导出
dept_salary.to_excel("各部门薪资统计.xlsx", index=True)
posted @ 2025-12-10 21:42  布衣开发者  阅读(309)  评论(0)    收藏  举报