当前位置:首页>python>Python 零基础100天—Day74 Pandas 数据处理

Python 零基础100天—Day74 Pandas 数据处理

  • 2026-08-25 01:05:13
Python 零基础100天—Day74 Pandas 数据处理

🐍 Python Day74:Pandas 数据处理 — 缺失值、分组与聚合

🕐 预计用时:2-3 小时 | 🎯 目标:掌握缺失值处理、数据筛选、排序、分组聚合和数据清洗


📖 今日目录

  1. 缺失值处理
  2. 数据筛选
  3. 排序
  4. 分组聚合(GroupBy)
  5. 数据清洗
  6. 数据变换
  7. 今日练习
  8. 今日小结

1. 缺失值处理

import pandas as pd
import numpy as np

df = pd.DataFrame({
    '姓名': ['小明', '小红', '小刚', '小美', '小强'],
    '年龄': [20, np.nan, 19, 22, np.nan],
    '城市': ['北京', '上海', None, '深圳', '杭州'],
    '薪资': [8000, 12000, 7500, np.nan, 9000]
})

# === 检测缺失值 ===
df.isnull()              # 返回布尔 DataFrame
df.isnull().sum()        # 每列缺失值数量
df.isnull().sum().sum()  # 总缺失值数量
df.isnull().mean()       # 每列缺失比例

# === 删除缺失值 ===
df.dropna()                    # 删除任何含缺失的行
df.dropna(subset=['年龄'])      # 只看'年龄'列,有缺失就删
df.dropna(how='all')           # 整行全为缺失才删
df.dropna(thresh=3)            # 至少有 3 个非缺失值才保留

# === 填充缺失值 ===
df.fillna(0)                   # 全部填 0
df['年龄'].fillna(df['年龄'].mean())     # 用均值填充
df['年龄'].fillna(df['年龄'].median())   # 用中位数填充
df['城市'].fillna('未知')                 # 用固定值
df.ffill()               # 用前一个非缺失值填充(前向填充)
df.bfill()               # 用后一个非缺失值填充(后向填充)
# 注:pandas 2.1+ 弃用了 fillna(method='ffill'),请用 df.ffill() / df.bfill()

# === 按列指定填充值 ===
df.fillna({'年龄': df['年龄'].mean(), '城市': '未知', '薪资': 0})

💡 缺失值处理策略:

• 数值列(年龄、薪资)→ 用均值或中位数填充
• 分类列(城市、性别)→ 用众数或"未知"填充
• 时间列(日期)→ 用前向/后向填充
• 缺失太多(>50%)→ 考虑删除该列


2. 数据筛选

import pandas as pd

df = pd.DataFrame({
    '姓名': ['小明', '小红', '小刚', '小美', '小强'],
    '年龄': [20, 21, 19, 22, 20],
    '城市': ['北京', '上海', '广州', '深圳', '杭州'],
    '薪资': [8000, 12000, 7500, 15000, 9000]
})

# === 单条件筛选 ===
df[df['年龄'] > 20]                    # 年龄大于 20
df[df['城市'] == '北京']                # 北京的人
df[df['薪资'] >= 10000]                # 高薪

# === 多条件筛选(& 与 / | 或)===
df[(df['年龄'] > 20) & (df['薪资'] > 10000)]    # 且
df[(df['城市'] == '北京') | (df['城市'] == '上海')]  # 或

# === isin 包含 ===
df[df['城市'].isin(['北京', '上海', '广州'])]

# === 字符串筛选 ===
df[df['姓名'].str.contains('小')]       # 包含"小"
df[df['姓名'].str.startswith('小')]     # 以"小"开头

# === between 范围 ===
df[df['年龄'].between(20, 22)]         # 年龄在 20-22 之间

# === 取反 ===
df[~df['城市'].isin(['北京', '上海'])]  # 不在北京和上海
df[df['年龄'] != 20]                    # 不等于 20

# === query 方法(字符串表达式,更易读)===
df.query('年龄 > 20')
df.query('年龄 > 20 and 薪资 > 10000')
df.query('城市 in ["北京", "上海"]')

# === 筛选并赋值 ===
df.loc[df['薪资'] < 8000, '薪资'] = 8000  # 低于 8000 的补到 8000

3. 排序

# 单列排序
df.sort_values('薪资')                            # 升序
df.sort_values('薪资', ascending=False)           # 降序

# 多列排序
df.sort_values(['年龄', '薪资'], ascending=[True, False])
# 先按年龄升序,年龄相同按薪资降序

# 索引排序
df.sort_index()                                   # 按索引排序

# 排名
df['薪资排名'] = df['薪资'].rank(ascending=False)  # 排名(1=最高)
df['薪资排名'] = df['薪资'].rank(method='dense')   # 密集排名(无间隔)
df['薪资排名'] = df['薪资'].rank(method='min')     # 最小排名

# Top N
df.nlargest(3, '薪资')    # 薪资最高的 3 个
df.nsmallest(3, '薪资')   # 薪资最低的 3 个

4. 分组聚合(GroupBy)

GroupBy 是 Pandas 最强大的功能——类似 Excel 的数据透视表。

import pandas as pd

df = pd.DataFrame({
    '姓名': ['小明', '小红', '小刚', '小美', '小强', '小丽'],
    '部门': ['技术', '市场', '技术', '市场', '技术', '市场'],
    '城市': ['北京', '上海', '北京', '上海', '广州', '广州'],
    '薪资': [15000, 12000, 18000, 15000, 16000, 13000]
})

# === 基本分组 ===
df.groupby('部门')['薪资'].mean()
# 部门
# 市场    13333.33
# 技术    16333.33

# === 多列分组 ===
df.groupby(['部门', '城市'])['薪资'].mean()

# === 多个聚合函数 ===
df.groupby('部门')['薪资'].agg(['mean', 'max', 'min', 'count', 'sum'])
#       mean    max    min  count    sum
# 部门
# 市场  13333  15000  12000      3  40000
# 技术  16333  18000  15000      3  49000

# === 不同列不同聚合 ===
df.groupby('部门').agg({
    '薪资': ['mean', 'max'],
    '姓名': 'count'
})

# === 对分组结果遍历 ===
for name, group in df.groupby('部门'):
    print(f'\n{name}部门:')
    print(group)

# === 分组后筛选 ===
# 找平均薪资最高的部门
df.groupby('部门')['薪资'].mean().idxmax()  # '技术'

# === transform(保持原 DataFrame 形状)===
# 每个人的薪资与部门均值的差
df['薪资偏差'] = df['薪资'] - df.groupby('部门')['薪资'].transform('mean')

# === 每组排序 ===
df.groupby('部门').apply(lambda x: x.nlargest(2, '薪资'))

💡 GroupBy 的核心公式:

df.groupby('分组列')['值列'].聚合函数()

常用聚合函数:mean()sum()count()max()min()std()agg([...])


5. 数据清洗

import pandas as pd

# === 去重 ===
df.duplicated()                          # 检查重复行(布尔)
df.duplicated(subset=['姓名', '城市'])    # 按指定列检查
df.drop_duplicates()                     # 删除重复行
df.drop_duplicates(subset=['姓名'])       # 按姓名去重,保留第一条
df.drop_duplicates(keep='last')          # 保留最后一条

# === 替换 ===
df['城市'].replace('北京', 'BJ')
df['城市'].replace({'北京': 'BJ', '上海': 'SH'})
df.replace({-999: np.nan, -1: np.nan})   # 多个异常值替换为 NaN

# === 重命名列 ===
df.rename(columns={'姓名': 'name', '年龄': 'age'})
df.columns = ['name', 'age', 'city', 'salary']  # 全部重命名

# === 删除列/行 ===
df.drop(columns=['年龄'])          # 删除列
df.drop(columns=['年龄', '城市'])   # 删除多列
df.drop(index=[0, 1])             # 删除行

# === 删除异常值 ===
# IQR 方法(四分位距)
Q1 = df['薪资'].quantile(0.25)
Q3 = df['薪资'].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
df_clean = df[(df['薪资'] >= lower) & (df['薪资'] <= upper)]

# === 字符串清洗 ===
df['姓名'] = df['姓名'].str.strip()      # 去首尾空格
df['姓名'] = df['姓名'].str.replace(' ', '', regex=False)  # 去所有空格
df['电话'] = df['电话'].str.replace('-', '', regex=False)  # 去横线

6. 数据变换

import pandas as pd
import numpy as np

# === 新增列 ===
df['年薪'] = df['薪资'] * 12
df['税后'] = df['薪资'] * 0.8

# === apply 自定义函数 ===
def level(salary):
    if salary >= 15000:
        return '高薪'
    elif salary >= 10000:
        return '中等'
    else:
        return '低薪'

df['薪资等级'] = df['薪资'].apply(level)

# apply + lambda(更简洁)
df['薪资等级'] = df['薪资'].apply(lambda x: '高薪' if x >= 15000 else '中等' if x >= 10000 else '低薪')

# 对多列 apply
df['描述'] = df.apply(lambda row: f"{row['姓名']}在{row['城市']}", axis=1)

# === map 映射 ===
city_map = {'北京': '华北', '上海': '华东', '广州': '华南'}
df['区域'] = df['城市'].map(city_map)

# === cut 分箱 ===
df['年龄段'] = pd.cut(df['年龄'],
                       bins=[0, 18, 25, 35, 100],
                       labels=['少年', '青年', '中年', '老年'])

# === qcut 等频分箱 ===
df['薪资等级'] = pd.qcut(df['薪资'], q=3, labels=['低', '中', '高'])

# === 透视表(pivot_table)===
pivot = df.pivot_table(
    values='薪资',
    index='部门',
    columns='城市',
    aggfunc='mean',
    fill_value=0
)

7. 今日练习

🏋️ 练习 1:销售数据清洗

# 给定一份脏数据(含缺失值、重复行、异常值):
# 1. 统计缺失值比例
# 2. 填充/删除缺失值
# 3. 去重
# 4. 删除异常值(IQR 方法)
# 5. 输出清洗后的数据

🏋️ 练习 2:分组分析

# 对电商订单数据:
# 1. 按品类分组,计算总销售额、平均单价、订单数
# 2. 找出每个品类销量 Top3 的商品
# 3. 按月统计销售趋势

🏋️ 练习 3:员工数据处理

# 创建员工 DataFrame:
# 1. 用 apply 计算工龄等级(<3年/3-10年/>10年)
# 2. 用 pivot_table 生成部门×城市的平均薪资透视表
# 3. 按部门分组,找出每组薪资最高的人

8. 今日小结

知识点
核心内容
缺失值
isnull / dropna / fillna(均值/中位数/前后填充)
筛选
条件筛选 / isin / between / str.contains / query
排序
sort_values / sort_index / nlargest / rank
分组
groupby + mean/sum/count/agg/transform
清洗
去重 / 替换 / 重命名 / 删除异常值
变换
apply / map / cut / pivot_table

🚀 明日预告:Day 75 — Pandas 数据合并

merge(类似 SQL JOIN)、concat(拼接)、透视表——多表关联是数据分析的日常操作。明天搞定它!

最新文章

随机文章