导航菜单

  • 1.langchain.intro
  • 2.langchain.chat_models
  • 3.langchain.prompts
  • 4.langchain.example_selectors
  • 5.output_parsers
  • 6.Runnable
  • 7.memory
  • 8.document_loaders
  • 9.text_splitters
  • 10.embeddings
  • 11.tool
  • 12.retrievers
  • 13.optimize
  • 14.项目介绍
  • 15.启动HTTP
  • 16.数据与模型
  • 17.权限管理
  • 18.知识库管理
  • 19.设置
  • 20.文档管理
  • 21.聊天
  • 22.API文档
  • 23.RAG优化
  • 24.索引时优化
  • 25.检索前优化
  • 26.检索后优化
  • 27.系统优化
  • 28.GraphRAG
  • 29.图
  • 30.为什么选择图数据库
  • 31.什么是 Neo4j
  • 32.安装和连接 Neo4j
  • 33.Neo4j核心概念
  • 34.Cypher基础
  • 35.模式匹配
  • 36.数据CRUD操作
  • 37.GraphRAG
  • 38.查询和过滤
  • 39.结果处理和聚合
  • 40.语句组合
  • 41.子查询
  • 42.模式和约束
  • 43.日期时间处理
  • 44.Cypher内置函数
  • 45.Python操作Neo4j
  • 46.neo4j
  • 47.py2neo
  • 48.Streamlit
  • 49.Pandas
  • 50.graphRAG
  • 51.deepdoc
  • 52.deepdoc
  • 53.deepdoc
  • 55.deepdoc
  • 54.deepdoc
  • Pillow
  • 1. Pandas 简介与安装
    • 1.1 什么是 Pandas?
    • 1.2 为什么学习 Pandas?
    • 1.3 安装 Pandas
    • 1.4 导入 Pandas
  • 2. 前置知识:NumPy 基础
    • 2.1 NumPy 数组
    • 2.2 为什么需要了解 NumPy?
  • 3. Series:一维数据结构
    • 3.1 什么是 Series?
    • 3.2 创建 Series
    • 3.3 访问 Series 数据
    • 3.4 Series 的基本操作
  • 4. DataFrame:二维表格数据
    • 4.1 什么是 DataFrame?
    • 4.2 创建 DataFrame
    • 4.3 DataFrame 的基本结构
  • 5. 数据读取与保存
    • 5.1 读取 CSV 文件
    • 5.2 读取 Excel 文件
    • 5.3 读取 JSON 文件
    • 5.4 保存数据
  • 6. 数据查看与探索
    • 6.1 查看数据的基本方法
    • 6.2 查看数据的形状和结构
  • 7. 数据选择与筛选
    • 7.1 选择列
    • 7.2 选择行
    • 7.3 条件筛选
  • 8. 数据清洗
    • 8.1 处理缺失值
    • 8.2 处理重复值
    • 8.3 数据类型转换
  • 9. 数据操作:增删改查
    • 9.1 添加列
    • 9.2 删除列
    • 9.3 添加行
    • 9.4 删除行
    • 9.5 修改数据
    • 9.6 重命名
    • 9.7 排序
  • 10. 数据分组与聚合
    • 10.1 基本分组操作
    • 10.2 聚合函数
    • 10.3 数据透视表
  • 11. 数据合并与连接
    • 11.1 使用 concat 合并
    • 11.2 使用 merge 连接
  • 12. 常用函数与技巧
    • 12.1 统计函数
    • 12.2 字符串操作
    • 12.3 应用函数(apply)
    • 12.4 条件判断(where)
  • 13. 综合实战案例
    • 13.1 案例:员工数据分析
    • 13.2 案例总结
  • 14. 总结

1. Pandas 简介与安装 #

1.1 什么是 Pandas? #

Pandas 是 Python 中最流行的数据处理和分析库,它的名字来源于"Panel Data"(面板数据)。Pandas 专门用于处理结构化数据,就像 Excel 表格一样,但功能更强大。

1.2 为什么学习 Pandas? #

  • 处理表格数据:可以轻松处理 CSV、Excel 等格式的数据
  • 数据清洗:快速处理缺失值、重复值等问题
  • 数据分析:进行分组、聚合、统计等操作
  • 数据可视化:配合 Matplotlib 等库进行数据可视化
  • 广泛应用:数据科学、金融分析、商业分析等领域必备工具

1.3 安装 Pandas #

# 在命令行或终端中执行以下命令安装 Pandas
# pip install pandas

# 如果需要读取 Excel 文件,还需要安装 openpyxl
# pip install openpyxl

1.4 导入 Pandas #

# 导入 pandas 库,通常简写为 pd
import pandas as pd

# 同时导入 numpy,因为 Pandas 依赖 NumPy
import numpy as np

# 打印 Pandas 版本(可选)
print(pd.__version__)

2. 前置知识:NumPy 基础 #

在学习 Pandas 之前,我们需要了解一些 NumPy 的基础知识,因为 Pandas 是基于 NumPy 构建的。

2.1 NumPy 数组 #

NumPy 提供了高效的数组操作,Pandas 内部使用 NumPy 数组来存储数据。

# 导入 numpy
import numpy as np

# 创建一维数组(类似 Python 列表)
arr = np.array([1, 2, 3, 4, 5])
print(arr)
# 输出:[1 2 3 4 5]

# 创建二维数组(类似表格)
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
print(arr_2d)
# 输出:
# [[1 2 3]
#  [4 5 6]]

# NumPy 的特殊值:NaN(Not a Number,表示缺失值)
nan_value = np.nan
print(nan_value)
# 输出:nan

2.2 为什么需要了解 NumPy? #

  • Pandas 的 Series 和 DataFrame 底层使用 NumPy 数组
  • 很多 Pandas 操作返回 NumPy 数组
  • 理解 NumPy 有助于理解 Pandas 的工作原理

3. Series:一维数据结构 #

3.1 什么是 Series? #

Series 是 Pandas 中最基本的数据结构,可以理解为"带标签的一维数组"。它类似于 Excel 中的一列数据,但每个数据都有对应的索引(标签)。

3.2 创建 Series #

# 导入必要的库
import pandas as pd
import numpy as np

# 方法1:从列表创建 Series(最简单的方式)
# 创建一个包含数字的列表
data_list = [10, 20, 30, 40, 50]
# 使用 pd.Series() 创建 Series,会自动生成索引 0, 1, 2, 3, 4
s1 = pd.Series(data_list)
print(s1)
# 输出:
# 0    10
# 1    20
# 2    30
# 3    40
# 4    50
# dtype: int64

# 方法2:从列表创建,并指定自定义索引
# 创建数据列表
data_list = [10, 20, 30, 40, 50]
# 创建索引列表(标签)
index_list = ['a', 'b', 'c', 'd', 'e']
# 使用 index 参数指定索引
s2 = pd.Series(data_list, index=index_list)
print(s2)
# 输出:
# a    10
# b    20
# c    30
# d    40
# e    50
# dtype: int64

# 方法3:从字典创建 Series(字典的键会成为索引)
# 创建字典,键是索引,值是数据
data_dict = {'a': 10, 'b': 20, 'c': 30, 'd': 40, 'e': 50}
# 从字典创建 Series
s3 = pd.Series(data_dict)
print(s3)
# 输出:
# a    10
# b    20
# c    30
# d    40
# e    50
# dtype: int64

# 方法4:创建包含缺失值的 Series
# np.nan 表示缺失值(Not a Number)
data_with_nan = [1, 3, 5, np.nan, 6, 8]
s4 = pd.Series(data_with_nan)
print(s4)
# 输出:
# 0    1.0
# 1    3.0
# 2    5.0
# 3    NaN
# 4    6.0
# 5    8.0
# dtype: float64

3.3 访问 Series 数据 #

# 创建示例 Series
s = pd.Series([10, 20, 30, 40, 50], index=['a', 'b', 'c', 'd', 'e'])

# 通过索引访问单个值
print(s['a'])
# 输出:10

# 通过位置访问(使用 iloc)
print(s.iloc[0])
# 输出:10

# 访问多个值(使用列表)
print(s[['a', 'c', 'e']])
# 输出:
# a    10
# c    30
# e    50
# dtype: int64

# 通过位置访问多个值
print(s.iloc[0:3])
# 输出:
# a    10
# b    20
# c    30
# dtype: int64

3.4 Series 的基本操作 #

# 创建示例 Series
s = pd.Series([10, 20, 30, 40, 50])

# 查看 Series 的基本信息
print(s.values)      # 获取所有值(返回 NumPy 数组)
# 输出:[10 20 30 40 50]

print(s.index)       # 获取索引
# 输出:RangeIndex(start=0, stop=5, step=1)

print(s.dtype)       # 获取数据类型
# 输出:int64

print(len(s))        # 获取长度
# 输出:5

# 数学运算(会对每个元素进行操作)
print(s * 2)
# 输出:
# 0    20
# 1    40
# 2    60
# 3    80
# 4    100
# dtype: int64

# 统计函数
print(s.mean())      # 平均值
# 输出:30.0

print(s.sum())       # 求和
# 输出:150

print(s.max())       # 最大值
# 输出:50

print(s.min())       # 最小值
# 输出:10

4. DataFrame:二维表格数据 #

4.1 什么是 DataFrame? #

DataFrame 是 Pandas 中最重要的数据结构,可以理解为"带标签的二维表格",就像 Excel 表格一样。它由多个 Series 组成,每一列是一个 Series。

4.2 创建 DataFrame #

# 导入必要的库
import pandas as pd
import numpy as np

# 方法1:从字典创建 DataFrame(最常用)
# 字典的键会成为列名,值会成为该列的数据
data_dict = {
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [25, 30, 35, 28],
    '城市': ['北京', '上海', '广州', '深圳'],
    '工资': [8000, 12000, 15000, 10000]
}
# 使用 pd.DataFrame() 创建 DataFrame
df = pd.DataFrame(data_dict)
print(df)
# 输出:
#    姓名  年龄  城市     工资
# 0  张三  25  北京   8000
# 1  李四  30  上海  12000
# 2  王五  35  广州  15000
# 3  赵六  28  深圳  10000

# 方法2:从列表的列表创建 DataFrame
# 先准备数据(每一行是一个列表)
data_list = [
    ['张三', 25, '北京', 8000],
    ['李四', 30, '上海', 12000],
    ['王五', 35, '广州', 15000],
    ['赵六', 28, '深圳', 10000]
]
# 使用 columns 参数指定列名
df2 = pd.DataFrame(data_list, columns=['姓名', '年龄', '城市', '工资'])
print(df2)
# 输出:同上

# 方法3:从字典列表创建 DataFrame
# 每个字典代表一行数据
data_dict_list = [
    {'姓名': '张三', '年龄': 25, '城市': '北京', '工资': 8000},
    {'姓名': '李四', '年龄': 30, '城市': '上海', '工资': 12000},
    {'姓名': '王五', '年龄': 35, '城市': '广州', '工资': 15000},
    {'姓名': '赵六', '年龄': 28, '城市': '深圳', '工资': 10000}
]
df3 = pd.DataFrame(data_dict_list)
print(df3)
# 输出:同上

# 方法4:创建空的 DataFrame,然后添加数据
# 创建只有列名的空 DataFrame
df4 = pd.DataFrame(columns=['姓名', '年龄', '城市', '工资'])
print(df4)
# 输出:空的 DataFrame

# 方法5:从 NumPy 数组创建
# 创建随机数据
np_data = np.random.randn(4, 3)  # 4行3列的随机数
df5 = pd.DataFrame(np_data, columns=['列1', '列2', '列3'])
print(df5)
# 输出:4行3列的随机数表格

4.3 DataFrame 的基本结构 #

# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [25, 30, 35, 28],
    '城市': ['北京', '上海', '广州', '深圳'],
    '工资': [8000, 12000, 15000, 10000]
})

# 查看 DataFrame 的基本信息
print(df.shape)          # 查看形状(行数, 列数)
# 输出:(4, 4)

print(df.columns)       # 查看列名
# 输出:Index(['姓名', '年龄', '城市', '工资'], dtype='object')

print(df.index)         # 查看索引
# 输出:RangeIndex(start=0, stop=4, step=1)

print(df.dtypes)        # 查看每列的数据类型
# 输出:
# 姓名    object
# 年龄     int64
# 城市    object
# 工资     int64
# dtype: object

print(df.size)          # 查看总元素数量(行数 × 列数)
# 输出:16

5. 数据读取与保存 #

5.1 读取 CSV 文件 #

CSV(Comma-Separated Values)是最常见的数据格式,用逗号分隔值。

# 导入必要的库
import pandas as pd

# 读取 CSV 文件
# 假设有一个名为 data.csv 的文件
# df = pd.read_csv('data.csv')

# 如果文件第一行不是列名,可以指定列名
# df = pd.read_csv('data.csv', names=['列1', '列2', '列3'])

# 如果文件使用其他分隔符(如分号),使用 sep 参数
# df = pd.read_csv('data.csv', sep=';')

# 如果文件有编码问题(中文乱码),指定编码
# df = pd.read_csv('data.csv', encoding='utf-8')
# 或者
# df = pd.read_csv('data.csv', encoding='gbk')

# 示例:创建一个 CSV 文件并读取
# 先创建一个示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五'],
    '年龄': [25, 30, 35],
    '城市': ['北京', '上海', '广州']
})

# 保存为 CSV 文件
df.to_csv('示例数据.csv', index=False, encoding='utf-8-sig')
# index=False 表示不保存行索引
# encoding='utf-8-sig' 确保中文正常显示

# 读取刚才保存的 CSV 文件
df_read = pd.read_csv('示例数据.csv', encoding='utf-8-sig')
print(df_read)

5.2 读取 Excel 文件 #

Excel 文件是另一种常见的数据格式。

# 导入必要的库
import pandas as pd

# 读取 Excel 文件(需要安装 openpyxl:pip install openpyxl)
# df = pd.read_excel('data.xlsx')

# 读取指定的工作表(sheet)
# df = pd.read_excel('data.xlsx', sheet_name='Sheet1')

# 读取多个工作表
# all_sheets = pd.read_excel('data.xlsx', sheet_name=None)
# 返回一个字典,键是工作表名,值是 DataFrame

# 示例:创建并读取 Excel 文件
# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五'],
    '年龄': [25, 30, 35],
    '城市': ['北京', '上海', '广州']
})

# 保存为 Excel 文件
df.to_excel('示例数据.xlsx', index=False, sheet_name='员工信息')
# index=False 表示不保存行索引
# sheet_name 指定工作表名称

# 读取 Excel 文件
df_read = pd.read_excel('示例数据.xlsx', sheet_name='员工信息')
print(df_read)

5.3 读取 JSON 文件 #

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。

# 导入必要的库
import pandas as pd

# 读取 JSON 文件
# df = pd.read_json('data.json')

# 如果 JSON 是嵌套格式,可能需要指定 orient 参数
# df = pd.read_json('data.json', orient='records')

# 示例:创建并读取 JSON 文件
# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五'],
    '年龄': [25, 30, 35],
    '城市': ['北京', '上海', '广州']
})

# 保存为 JSON 文件
df.to_json('示例数据.json', orient='records', force_ascii=False)
# orient='records' 表示每行数据作为一个 JSON 对象
# force_ascii=False 确保中文正常显示

# 读取 JSON 文件
df_read = pd.read_json('示例数据.json')
print(df_read)

5.4 保存数据 #

# 导入必要的库
import pandas as pd

# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五'],
    '年龄': [25, 30, 35],
    '城市': ['北京', '上海', '广州']
})

# 保存为 CSV(最常用)
df.to_csv('输出数据.csv', index=False, encoding='utf-8-sig')
# index=False 不保存行索引
# encoding='utf-8-sig' 确保中文正常显示

# 保存为 Excel
df.to_excel('输出数据.xlsx', index=False, sheet_name='数据')

# 保存为 JSON
df.to_json('输出数据.json', orient='records', force_ascii=False)

6. 数据查看与探索 #

6.1 查看数据的基本方法 #

在开始分析数据之前,我们需要先了解数据的基本情况。

# 导入必要的库
import pandas as pd
import numpy as np

# 创建示例 DataFrame(模拟真实数据)
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十'],
    '年龄': [25, 30, 35, 28, 32, 27, 29, 31],
    '城市': ['北京', '上海', '广州', '深圳', '北京', '上海', '广州', '深圳'],
    '工资': [8000, 12000, 15000, 10000, 9000, 13000, 16000, 11000],
    '部门': ['销售', '技术', '技术', '销售', '技术', '销售', '技术', '销售']
})

# 查看前几行数据(默认前5行)
print(df.head())
# 输出:前5行数据

# 查看前 n 行
print(df.head(3))
# 输出:前3行数据

# 查看后几行数据(默认后5行)
print(df.tail())
# 输出:后5行数据

# 查看后 n 行
print(df.tail(3))
# 输出:后3行数据

# 查看数据的基本信息(非常重要!)
print(df.info())
# 输出:
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 8 entries, 0 to 7
# Data columns (total 5 columns):
#  #   Column  Non-Null Count  Dtype
#     --  --
#  0   姓名     8 non-null      object
#  1   年龄     8 non-null      int64
#  2   城市     8 non-null      object
#  3   工资     8 non-null      int64
#  4   部门     8 non-null      object
# dtypes: int64(2), object(3)
# memory usage: 448.0+ bytes

# 查看数据的统计描述(只对数值列有效)
print(df.describe())
# 输出:
#              年龄          工资
# count   8.000000     8.000000
# mean   29.625000 11625.000000
# std     3.204164  2906.797181
# min    25.000000  8000.000000
# 25%    27.750000  9500.000000
# 50%    29.500000 11500.000000
# 75%    31.250000 13500.000000
# max    35.000000 16000.000000

6.2 查看数据的形状和结构 #

# 继续使用上面的 df

# 查看数据的形状(行数, 列数)
print(df.shape)
# 输出:(8, 5)  # 8行5列

# 查看列名
print(df.columns)
# 输出:Index(['姓名', '年龄', '城市', '工资', '部门'], dtype='object')

# 查看索引
print(df.index)
# 输出:RangeIndex(start=0, stop=8, step=1)

# 查看每列的数据类型
print(df.dtypes)
# 输出:
# 姓名    object
# 年龄     int64
# 城市    object
# 工资     int64
# 部门    object
# dtype: object

# 查看是否有缺失值
print(df.isnull().sum())
# 输出:每列的缺失值数量(这里都是0,因为没有缺失值)

# 查看总元素数量
print(df.size)
# 输出:40  # 8行 × 5列 = 40

7. 数据选择与筛选 #

7.1 选择列 #

选择列是数据分析中最常用的操作之一。

# 导入必要的库
import pandas as pd

# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [25, 30, 35, 28],
    '城市': ['北京', '上海', '广州', '深圳'],
    '工资': [8000, 12000, 15000, 10000]
})

# 方法1:使用方括号选择单列(返回 Series)
name_column = df['姓名']
print(name_column)
# 输出:
# 0    张三
# 1    李四
# 2    王五
# 3    赵六
# Name: 姓名, dtype: object

# 方法2:使用点号选择单列(仅当列名无空格时可用)
age_column = df.年龄
print(age_column)
# 输出:
# 0    25
# 1    30
# 2    35
# 3    28
# Name: 年龄, dtype: int64

# 方法3:选择多列(使用列表,返回 DataFrame)
name_age = df[['姓名', '年龄']]
print(name_age)
# 输出:
#    姓名  年龄
# 0  张三  25
# 1  李四  30
# 2  王五  35
# 3  赵六  28

7.2 选择行 #

# 继续使用上面的 df

# 方法1:使用 iloc 按位置选择行(最常用)
# iloc 是 "integer location" 的缩写,按整数位置选择

# 选择第一行(索引从0开始)
first_row = df.iloc[0]
print(first_row)
# 输出:
# 姓名    张三
# 年龄    25
# 城市    北京
# 工资    8000
# Name: 0, dtype: object

# 选择前3行
first_three = df.iloc[0:3]
print(first_three)
# 输出:前3行数据

# 选择特定行(使用列表)
specific_rows = df.iloc[[0, 2]]
print(specific_rows)
# 输出:第1行和第3行

# 方法2:使用 loc 按标签选择行
# loc 是 "location" 的缩写,按标签(索引)选择

# 选择索引为0的行
row_0 = df.loc[0]
print(row_0)

# 选择索引0到2的行(包含2)
rows_0_to_2 = df.loc[0:2]
print(rows_0_to_2)

# 方法3:同时选择行和列
# 选择前2行的姓名和年龄列
subset = df.loc[0:1, ['姓名', '年龄']]
print(subset)
# 输出:
#    姓名  年龄
# 0  张三  25
# 1  李四  30

# 使用 iloc 也可以
subset2 = df.iloc[0:2, [0, 1]]
print(subset2)

7.3 条件筛选 #

条件筛选是数据分析的核心功能,可以根据条件选择满足要求的数据。

# 继续使用上面的 df

# 简单条件筛选:选择年龄大于25的员工
age_filter = df[df['年龄'] > 25]
print(age_filter)
# 输出:年龄大于25的所有行

# 多条件筛选:使用 &(且)和 |(或)
# 注意:每个条件必须用括号括起来

# 选择年龄大于25且工资大于10000的员工
complex_filter = df[(df['年龄'] > 25) & (df['工资'] > 10000)]
print(complex_filter)
# 输出:同时满足两个条件的行

# 选择年龄大于30或工资大于12000的员工
or_filter = df[(df['年龄'] > 30) | (df['工资'] > 12000)]
print(or_filter)
# 输出:满足任一条件的行

# 使用 isin() 方法:选择城市在北京或上海的员工
city_filter = df[df['城市'].isin(['北京', '上海'])]
print(city_filter)
# 输出:城市为北京或上海的所有行

# 使用字符串方法筛选:选择姓名包含"三"的员工
name_filter = df[df['姓名'].str.contains('三')]
print(name_filter)
# 输出:姓名包含"三"的行

8. 数据清洗 #

8.1 处理缺失值 #

真实数据中经常会有缺失值(NaN),需要处理才能进行分析。

# 导入必要的库
import pandas as pd
import numpy as np

# 创建包含缺失值的示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '赵六', '钱七'],
    '年龄': [25, 30, np.nan, 28, 32],
    '城市': ['北京', '上海', '广州', np.nan, '深圳'],
    '工资': [8000, 12000, 15000, np.nan, 9000]
})

print("原始数据:")
print(df)

# 检查缺失值
# isnull() 返回布尔值 DataFrame,True 表示缺失值
print("\n缺失值检查:")
print(df.isnull())
# 输出:每个位置是否为缺失值

# 统计每列的缺失值数量
print("\n每列缺失值数量:")
print(df.isnull().sum())
# 输出:
# 姓名    0
# 年龄    1
# 城市    1
# 工资    1
# dtype: int64

# 检查是否有缺失值(返回 True/False)
print("\n是否有缺失值:")
print(df.isnull().any().any())
# 输出:True

# 处理缺失值的方法1:删除包含缺失值的行
df_dropna = df.dropna()
print("\n删除缺失值后:")
print(df_dropna)
# 输出:只保留没有缺失值的行

# 处理缺失值的方法2:填充缺失值
# 用固定值填充
df_fill_0 = df.fillna(0)
print("\n用0填充后:")
print(df_fill_0)

# 用前一个值填充(前向填充)
df_ffill = df.fillna(method='ffill')
print("\n前向填充后:")
print(df_ffill)

# 用后一个值填充(后向填充)
df_bfill = df.fillna(method='bfill')
print("\n后向填充后:")
print(df_bfill)

# 用列的均值填充(只对数值列有效)
df_fill_mean = df.copy()
df_fill_mean['年龄'].fillna(df_fill_mean['年龄'].mean(), inplace=True)
df_fill_mean['工资'].fillna(df_fill_mean['工资'].mean(), inplace=True)
print("\n用均值填充数值列后:")
print(df_fill_mean)

# 用字典指定不同列的填充值
df_fill_dict = df.fillna({
    '年龄': df['年龄'].mean(),
    '城市': '未知',
    '工资': df['工资'].mean()
})
print("\n用字典指定填充值后:")
print(df_fill_dict)

8.2 处理重复值 #

# 导入必要的库
import pandas as pd

# 创建包含重复值的示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '张三', '李四'],
    '年龄': [25, 30, 35, 25, 30],
    '城市': ['北京', '上海', '广州', '北京', '上海']
})

print("原始数据:")
print(df)

# 检查重复行
print("\n重复行检查:")
print(df.duplicated())
# 输出:每行是否为重复行(True/False)

# 查看重复的行
print("\n重复的行:")
print(df[df.duplicated()])
# 输出:所有重复的行

# 删除重复行(保留第一次出现的)
df_no_dup = df.drop_duplicates()
print("\n删除重复行后:")
print(df_no_dup)

# 根据特定列判断重复
# 只根据'姓名'列判断重复
df_no_dup_name = df.drop_duplicates(subset=['姓名'])
print("\n根据姓名删除重复后:")
print(df_no_dup_name)

# 保留最后一次出现的重复行
df_keep_last = df.drop_duplicates(keep='last')
print("\n保留最后一次出现的重复行:")
print(df_keep_last)

8.3 数据类型转换 #

# 导入必要的库
import pandas as pd

# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五'],
    '年龄': ['25', '30', '35'],  # 字符串类型
    '工资': ['8000', '12000', '15000']  # 字符串类型
})

print("原始数据类型:")
print(df.dtypes)

# 转换单列数据类型
# 将年龄列转换为整数
df['年龄'] = df['年龄'].astype('int')
print("\n转换年龄列后:")
print(df.dtypes)

# 将工资列转换为浮点数
df['工资'] = df['工资'].astype('float')
print("\n转换工资列后:")
print(df.dtypes)

# 转换日期类型
# 创建包含日期的 DataFrame
df_date = pd.DataFrame({
    '日期': ['2023-01-01', '2023-02-01', '2023-03-01']
})
# 转换为日期类型
df_date['日期'] = pd.to_datetime(df_date['日期'])
print("\n日期转换后:")
print(df_date.dtypes)
print(df_date)

# 使用 pd.to_numeric() 转换(更安全,可以处理错误)
df_safe = pd.DataFrame({
    '数值': ['1', '2', 'abc', '4']
})
# errors='coerce' 表示遇到错误时转换为 NaN
df_safe['数值'] = pd.to_numeric(df_safe['数值'], errors='coerce')
print("\n安全转换后:")
print(df_safe)

9. 数据操作:增删改查 #

9.1 添加列 #

# 导入必要的库
import pandas as pd

# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五'],
    '年龄': [25, 30, 35],
    '工资': [8000, 12000, 15000]
})

print("原始数据:")
print(df)

# 方法1:直接赋值添加新列
df['奖金'] = [1000, 2000, 3000]
print("\n添加奖金列后:")
print(df)

# 方法2:基于现有列计算新列
df['总工资'] = df['工资'] + df['奖金']
print("\n添加总工资列后:")
print(df)

# 方法3:使用 assign() 方法(不修改原 DataFrame,返回新 DataFrame)
df_new = df.assign(绩效 = [500, 600, 700])
print("\n使用 assign 添加列后:")
print(df_new)

9.2 删除列 #

# 继续使用上面的 df

# 方法1:使用 drop() 方法(不修改原 DataFrame,返回新 DataFrame)
df_dropped = df.drop('奖金', axis=1)
print("删除奖金列后:")
print(df_dropped)

# 方法2:使用 drop() 并设置 inplace=True(直接修改原 DataFrame)
df.drop('总工资', axis=1, inplace=True)
print("\n直接删除总工资列后:")
print(df)

# 删除多列
df_dropped_multi = df.drop(['奖金', '总工资'], axis=1)
print("\n删除多列后:")
print(df_dropped_multi)

9.3 添加行 #

# 继续使用上面的 df

# 方法1:使用 append() 方法(已弃用,但可以用)
# 创建新行数据
new_row = pd.Series({
    '姓名': '赵六',
    '年龄': 28,
    '工资': 10000
})
# 添加到 DataFrame
df = df.append(new_row, ignore_index=True)
print("添加新行后:")
print(df)

# 方法2:使用 pd.concat() 方法(推荐)
# 创建新的 DataFrame
new_df = pd.DataFrame({
    '姓名': ['钱七'],
    '年龄': [32],
    '工资': [11000]
})
# 合并
df = pd.concat([df, new_df], ignore_index=True)
print("\n使用 concat 添加行后:")
print(df)

9.4 删除行 #

# 继续使用上面的 df

# 删除指定索引的行
df_dropped_row = df.drop(0)  # 删除第一行
print("删除第一行后:")
print(df_dropped_row)

# 删除多行
df_dropped_rows = df.drop([0, 1])  # 删除第1行和第2行
print("\n删除多行后:")
print(df_dropped_rows)

# 根据条件删除行
df_filtered = df[df['年龄'] > 30]  # 保留年龄大于30的行
print("\n根据条件筛选后:")
print(df_filtered)

9.5 修改数据 #

# 继续使用上面的 df

# 修改单个值
df.loc[0, '工资'] = 9000
print("修改单个值后:")
print(df)

# 修改整列
df['工资'] = df['工资'] * 1.1  # 工资增加10%
print("\n修改整列后:")
print(df)

# 根据条件修改
df.loc[df['年龄'] > 30, '工资'] = df.loc[df['年龄'] > 30, '工资'] * 1.2
print("\n根据条件修改后:")
print(df)

9.6 重命名 #

# 继续使用上面的 df

# 重命名列
df_renamed = df.rename(columns={'姓名': '名字', '年龄': '岁数'})
print("重命名列后:")
print(df_renamed)

# 重命名索引
df_renamed_index = df.rename(index={0: '第一行', 1: '第二行'})
print("\n重命名索引后:")
print(df_renamed_index)

9.7 排序 #

# 继续使用上面的 df

# 按单列排序(默认升序)
df_sorted = df.sort_values('年龄')
print("按年龄升序排序:")
print(df_sorted)

# 按单列降序排序
df_sorted_desc = df.sort_values('年龄', ascending=False)
print("\n按年龄降序排序:")
print(df_sorted_desc)

# 按多列排序
df_sorted_multi = df.sort_values(['城市', '年龄'])
print("\n按城市和年龄排序:")
print(df_sorted_multi)

# 按索引排序
df_sorted_index = df.sort_index()
print("\n按索引排序:")
print(df_sorted_index)

10. 数据分组与聚合 #

10.1 基本分组操作 #

分组是数据分析中非常重要的操作,可以将数据按照某个标准分组,然后对每组进行统计分析。

# 导入必要的库
import pandas as pd

# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '赵六', '钱七', '孙八'],
    '部门': ['销售', '技术', '技术', '销售', '技术', '销售'],
    '城市': ['北京', '上海', '北京', '上海', '广州', '北京'],
    '工资': [8000, 12000, 15000, 10000, 13000, 9000],
    '年龄': [25, 30, 35, 28, 32, 27]
})

print("原始数据:")
print(df)

# 基本分组:按部门分组
grouped = df.groupby('部门')
print("\n分组对象:")
print(grouped)
# 输出:<pandas.core.groupby.generic.DataFrameGroupBy object at ...>

# 查看每个组
print("\n每个组的数据:")
for name, group in grouped:
    print(f"\n{name} 部门:")
    print(group)

# 对分组后的数据进行聚合操作
# 计算每个部门的平均工资
avg_salary = df.groupby('部门')['工资'].mean()
print("\n每个部门的平均工资:")
print(avg_salary)
# 输出:
# 部门
# 技术    13333.333333
# 销售     9000.000000
# Name: 工资, dtype: float64

# 计算每个部门的工资总和
sum_salary = df.groupby('部门')['工资'].sum()
print("\n每个部门的工资总和:")
print(sum_salary)

# 多重分组:按部门和城市分组
multi_grouped = df.groupby(['部门', '城市'])
print("\n多重分组后的平均工资:")
print(multi_grouped['工资'].mean())

10.2 聚合函数 #

# 继续使用上面的 df

# 使用 agg() 方法进行多种聚合操作
# 对工资列计算多个统计量
agg_result = df.groupby('部门')['工资'].agg(['mean', 'sum', 'min', 'max', 'count'])
print("每个部门工资的多种统计:")
print(agg_result)
# 输出:
#            mean      sum    min    max  count
# 部门
# 技术   13333.33   40000  12000  15000      3
# 销售    9000.00   27000   8000  10000      3

# 对不同列使用不同的聚合函数
agg_multi = df.groupby('部门').agg({
    '工资': ['mean', 'sum'],
    '年龄': 'mean'
})
print("\n对不同列使用不同聚合函数:")
print(agg_multi)

# 自定义聚合函数
def salary_range(series):
    """计算工资范围"""
    return series.max() - series.min()

custom_agg = df.groupby('部门')['工资'].agg(salary_range)
print("\n自定义聚合函数(工资范围):")
print(custom_agg)

10.3 数据透视表 #

数据透视表是 Excel 中常用的功能,Pandas 也提供了类似的功能。

# 继续使用上面的 df

# 创建数据透视表
# 以部门为行,城市为列,工资为值,计算平均值
pivot_table = pd.pivot_table(
    df,
    values='工资',      # 要聚合的列
    index='部门',       # 行索引
    columns='城市',     # 列索引
    aggfunc='mean'      # 聚合函数
)
print("数据透视表:")
print(pivot_table)
# 输出:
# 城市    北京     上海     广州
# 部门
# 技术  15000.0  12000.0  13000.0
# 销售   8500.0  10000.0     NaN

# 如果某个组合没有数据,会显示 NaN
# 可以指定 fill_value 填充缺失值
pivot_table_filled = pd.pivot_table(
    df,
    values='工资',
    index='部门',
    columns='城市',
    aggfunc='mean',
    fill_value=0  # 用0填充缺失值
)
print("\n填充缺失值后的透视表:")
print(pivot_table_filled)

11. 数据合并与连接 #

11.1 使用 concat 合并 #

concat 用于简单地将多个 DataFrame 合并在一起。

# 导入必要的库
import pandas as pd

# 创建两个示例 DataFrame
df1 = pd.DataFrame({
    '姓名': ['张三', '李四'],
    '年龄': [25, 30],
    '城市': ['北京', '上海']
})

df2 = pd.DataFrame({
    '姓名': ['王五', '赵六'],
    '年龄': [35, 28],
    '城市': ['广州', '深圳']
})

print("df1:")
print(df1)
print("\ndf2:")
print(df2)

# 纵向合并(上下合并,增加行)
df_vertical = pd.concat([df1, df2], ignore_index=True)
print("\n纵向合并后:")
print(df_vertical)
# 输出:4行数据

# 横向合并(左右合并,增加列)
df3 = pd.DataFrame({
    '工资': [8000, 12000],
    '部门': ['销售', '技术']
})

df_horizontal = pd.concat([df1, df3], axis=1)
print("\n横向合并后:")
print(df_horizontal)
# 输出:2行,5列

11.2 使用 merge 连接 #

merge 类似于 SQL 中的 JOIN 操作,根据共同的列连接两个 DataFrame。

# 导入必要的库
import pandas as pd

# 创建两个示例 DataFrame
# 员工信息表
df_employees = pd.DataFrame({
    '员工ID': [1, 2, 3, 4],
    '姓名': ['张三', '李四', '王五', '赵六'],
    '部门ID': [101, 102, 101, 103]
})

# 部门信息表
df_departments = pd.DataFrame({
    '部门ID': [101, 102, 103],
    '部门名称': ['销售部', '技术部', '财务部']
})

print("员工表:")
print(df_employees)
print("\n部门表:")
print(df_departments)

# 内连接(inner join):只保留两个表中都有的记录
df_inner = pd.merge(df_employees, df_departments, on='部门ID', how='inner')
print("\n内连接结果:")
print(df_inner)
# 输出:只包含有对应部门的员工

# 左连接(left join):保留左表的所有记录
df_left = pd.merge(df_employees, df_departments, on='部门ID', how='left')
print("\n左连接结果:")
print(df_left)
# 输出:包含所有员工,没有部门的显示 NaN

# 右连接(right join):保留右表的所有记录
df_right = pd.merge(df_employees, df_departments, on='部门ID', how='right')
print("\n右连接结果:")
print(df_right)
# 输出:包含所有部门,没有员工的显示 NaN

# 外连接(outer join):保留两个表的所有记录
df_outer = pd.merge(df_employees, df_departments, on='部门ID', how='outer')
print("\n外连接结果:")
print(df_outer)
# 输出:包含所有员工和所有部门

# 如果连接键的列名不同,使用 left_on 和 right_on
df_employees2 = pd.DataFrame({
    '员工ID': [1, 2, 3],
    '姓名': ['张三', '李四', '王五'],
    '部门编号': [101, 102, 101]  # 注意列名不同
})

df_merge_diff = pd.merge(
    df_employees2,
    df_departments,
    left_on='部门编号',
    right_on='部门ID',
    how='inner'
)
print("\n不同列名连接:")
print(df_merge_diff)

12. 常用函数与技巧 #

12.1 统计函数 #

# 导入必要的库
import pandas as pd
import numpy as np

# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [25, 30, 35, 28],
    '工资': [8000, 12000, 15000, 10000]
})

print("原始数据:")
print(df)

# 基本统计函数(只对数值列有效)
print("\n平均值:")
print(df.mean())
# 输出:每列的平均值

print("\n总和:")
print(df.sum())
# 输出:每列的总和

print("\n最大值:")
print(df.max())
# 输出:每列的最大值

print("\n最小值:")
print(df.min())
# 输出:每列的最小值

print("\n标准差:")
print(df.std())
# 输出:每列的标准差

print("\n计数:")
print(df.count())
# 输出:每列的非空值数量

# 对单列使用统计函数
print("\n年龄列的平均值:")
print(df['年龄'].mean())
# 输出:29.5

print("\n工资列的总和:")
print(df['工资'].sum())
# 输出:45000

12.2 字符串操作 #

Pandas 提供了强大的字符串操作方法,可以方便地处理文本数据。

# 导入必要的库
import pandas as pd

# 创建包含字符串的示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '赵六'],
    '邮箱': ['zhangsan@example.com', 'lisi@test.com', 'wangwu@demo.com', 'zhaoliu@sample.com'],
    '地址': ['北京市朝阳区', '上海市浦东新区', '广州市天河区', '深圳市南山区']
})

print("原始数据:")
print(df)

# 字符串转大写
df['姓名大写'] = df['姓名'].str.upper()
print("\n姓名转大写:")
print(df[['姓名', '姓名大写']])

# 字符串转小写
df['邮箱小写'] = df['邮箱'].str.lower()
print("\n邮箱转小写:")
print(df[['邮箱', '邮箱小写']])

# 检查字符串是否包含某个子串
df['包含北京'] = df['地址'].str.contains('北京')
print("\n检查是否包含'北京':")
print(df[['地址', '包含北京']])

# 字符串替换
df['地址替换'] = df['地址'].str.replace('区', '区(已处理)')
print("\n字符串替换:")
print(df[['地址', '地址替换']])

# 提取字符串的一部分
df['城市'] = df['地址'].str[:2]  # 提取前2个字符
print("\n提取城市:")
print(df[['地址', '城市']])

# 字符串长度
df['地址长度'] = df['地址'].str.len()
print("\n地址长度:")
print(df[['地址', '地址长度']])

12.3 应用函数(apply) #

apply 方法可以对 DataFrame 的行或列应用自定义函数。

# 导入必要的库
import pandas as pd

# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五'],
    '年龄': [25, 30, 35],
    '工资': [8000, 12000, 15000]
})

print("原始数据:")
print(df)

# 对单列应用函数
# 使用 lambda 函数:工资增加10%
df['新工资'] = df['工资'].apply(lambda x: x * 1.1)
print("\n工资增加10%:")
print(df[['姓名', '工资', '新工资']])

# 定义自定义函数
def categorize_age(age):
    """根据年龄分类"""
    if age < 30:
        return '年轻'
    elif age < 35:
        return '中年'
    else:
        return '资深'

# 应用自定义函数
df['年龄分类'] = df['年龄'].apply(categorize_age)
print("\n年龄分类:")
print(df[['姓名', '年龄', '年龄分类']])

# 对整行应用函数
def calculate_total(row):
    """计算总薪资(假设有奖金)"""
    return row['工资'] * 1.2

df['总薪资'] = df.apply(calculate_total, axis=1)
print("\n计算总薪资:")
print(df[['姓名', '工资', '总薪资']])
# axis=1 表示对每一行应用函数
# axis=0 表示对每一列应用函数

12.4 条件判断(where) #

# 导入必要的库
import pandas as pd
import numpy as np

# 创建示例 DataFrame
df = pd.DataFrame({
    '姓名': ['张三', '李四', '王五', '赵六'],
    '年龄': [25, 30, 35, 28],
    '工资': [8000, 12000, 15000, 10000]
})

print("原始数据:")
print(df)

# 使用 np.where() 进行条件判断
# 语法:np.where(条件, 满足条件的值, 不满足条件的值)
df['工资等级'] = np.where(df['工资'] > 10000, '高', '低')
print("\n工资等级:")
print(df[['姓名', '工资', '工资等级']])

# 多个条件
df['年龄组'] = np.where(
    df['年龄'] < 30,
    '年轻',
    np.where(df['年龄'] < 35, '中年', '资深')
)
print("\n年龄组:")
print(df[['姓名', '年龄', '年龄组']])

13. 综合实战案例 #

13.1 案例:员工数据分析 #

让我们通过一个完整的案例来综合运用前面学到的知识。

# 导入必要的库
import pandas as pd
import numpy as np

# 步骤1:创建模拟数据
# 在实际工作中,这些数据通常来自文件或数据库
np.random.seed(42)  # 设置随机种子,确保结果可重复

# 创建员工数据
data = {
    '员工ID': range(1, 21),
    '姓名': [f'员工{i}' for i in range(1, 21)],
    '部门': np.random.choice(['销售', '技术', '财务', '人事'], 20),
    '城市': np.random.choice(['北京', '上海', '广州', '深圳'], 20),
    '年龄': np.random.randint(22, 45, 20),
    '工资': np.random.randint(6000, 20000, 20),
    '入职年份': np.random.randint(2018, 2024, 20)
}

df = pd.DataFrame(data)

# 添加一些缺失值(模拟真实数据)
df.loc[2, '工资'] = np.nan
df.loc[5, '城市'] = np.nan
df.loc[8, '年龄'] = np.nan

print("步骤1:原始数据")
print(df.head(10))
print(f"\n数据形状:{df.shape}")
print(f"\n缺失值统计:\n{df.isnull().sum()}")

# 步骤2:数据清洗
print("\n" + "="*50)
print("步骤2:数据清洗")

# 处理缺失值
# 工资用中位数填充
df['工资'].fillna(df['工资'].median(), inplace=True)
# 城市用众数填充
df['城市'].fillna(df['城市'].mode()[0], inplace=True)
# 年龄用均值填充
df['年龄'].fillna(df['年龄'].mean(), inplace=True)

print("处理缺失值后:")
print(f"缺失值统计:\n{df.isnull().sum()}")

# 检查并删除重复值
duplicates = df.duplicated().sum()
print(f"\n重复行数量:{duplicates}")
if duplicates > 0:
    df.drop_duplicates(inplace=True)

# 步骤3:数据探索
print("\n" + "="*50)
print("步骤3:数据探索")

# 基本统计信息
print("\n数值列统计描述:")
print(df.describe())

# 各部门人数
print("\n各部门人数:")
print(df['部门'].value_counts())

# 各城市人数
print("\n各城市人数:")
print(df['城市'].value_counts())

# 步骤4:数据分析
print("\n" + "="*50)
print("步骤4:数据分析")

# 各部门平均工资
print("\n各部门平均工资:")
dept_avg_salary = df.groupby('部门')['工资'].mean().sort_values(ascending=False)
print(dept_avg_salary)

# 各城市平均工资
print("\n各城市平均工资:")
city_avg_salary = df.groupby('城市')['工资'].mean().sort_values(ascending=False)
print(city_avg_salary)

# 各部门的详细统计
print("\n各部门详细统计:")
dept_stats = df.groupby('部门').agg({
    '工资': ['mean', 'min', 'max', 'count'],
    '年龄': 'mean'
})
print(dept_stats)

# 步骤5:数据筛选
print("\n" + "="*50)
print("步骤5:数据筛选")

# 筛选高薪员工(工资 > 15000)
high_salary = df[df['工资'] > 15000]
print(f"\n高薪员工(工资>15000)数量:{len(high_salary)}")
print(high_salary[['姓名', '部门', '工资']])

# 筛选年轻员工(年龄 < 30)
young_employees = df[df['年龄'] < 30]
print(f"\n年轻员工(年龄<30)数量:{len(young_employees)}")

# 复合条件:技术部门且工资 > 12000
tech_high = df[(df['部门'] == '技术') & (df['工资'] > 12000)]
print(f"\n技术部门高薪员工数量:{len(tech_high)}")
print(tech_high[['姓名', '工资']])

# 步骤6:数据操作
print("\n" + "="*50)
print("步骤6:数据操作")

# 添加新列:工资等级
df['工资等级'] = np.where(
    df['工资'] < 10000, '低',
    np.where(df['工资'] < 15000, '中', '高')
)

# 添加新列:工作年限
df['工作年限'] = 2024 - df['入职年份']

# 添加新列:年薪
df['年薪'] = df['工资'] * 12

print("\n添加新列后的数据:")
print(df[['姓名', '部门', '工资', '工资等级', '工作年限', '年薪']].head())

# 步骤7:数据透视表
print("\n" + "="*50)
print("步骤7:数据透视表")

# 创建透视表:部门 vs 城市,显示平均工资
pivot = pd.pivot_table(
    df,
    values='工资',
    index='部门',
    columns='城市',
    aggfunc='mean',
    fill_value=0
)
print("\n部门 vs 城市 平均工资透视表:")
print(pivot)

# 步骤8:保存结果
print("\n" + "="*50)
print("步骤8:保存结果")

# 保存清洗后的数据
df.to_csv('员工数据_清洗后.csv', index=False, encoding='utf-8-sig')
print("数据已保存到:员工数据_清洗后.csv")

# 保存分析结果
dept_stats.to_csv('部门统计.csv', encoding='utf-8-sig')
print("部门统计已保存到:部门统计.csv")

print("\n" + "="*50)
print("分析完成!")

13.2 案例总结 #

这个案例涵盖了:

  1. 数据创建:创建模拟数据
  2. 数据清洗:处理缺失值和重复值
  3. 数据探索:查看基本统计信息
  4. 数据分析:分组聚合分析
  5. 数据筛选:条件筛选
  6. 数据操作:添加新列
  7. 数据透视:创建透视表
  8. 数据保存:保存结果

14. 总结 #

  1. Series 和 DataFrame:Pandas 的两个核心数据结构
  2. 数据读取与保存:处理各种文件格式
  3. 数据查看:了解数据的基本情况
  4. 数据选择:选择需要的行和列
  5. 数据清洗:处理缺失值和重复值
  6. 数据操作:增删改查
  7. 数据分组:分组聚合分析
  8. 数据合并:合并多个数据源
  9. 常用函数:统计、字符串、应用函数
← 上一节 48.Streamlit 下一节 50.graphRAG →

访问验证

请输入访问令牌

Token不正确,请重新输入