第一章 导论


1.1 介绍


功能 Excel Python(Pandas)
数据处理量 1万行以内 100万行以上
自动化 手动操作 代码一键运行
学习难度 简单 需要基础编程知识

数据分析的完整流程

  • 数据收集
  • 数据清洗
  • 数据分析
  • 数据可视化

数据分析工具链

  • Numpy:高性能数值计算(矩阵/向量) 数据的”发动机”
  • Pandas:表格数据处理(类似高级Excel) 数据的”手术刀”
  • Matplotlib:数据可视化(绘图库) 数据的”翻译官”

第二章 Numpy科学计算


2.1 Numpy介绍


numpy是python中科学计算的基础包

它是一个Python库,提供多维数组对象、各种派生对象(例如掩码数组和矩阵)以及用于对数组进行快速操作的各种方法,包括数学、逻辑、形状操作、排序、选择、I/O、离散、傅立叶变换、基本线性代数、基本统计运算、随机模拟等等

部分功能如下:

  • ndarray:一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组
  • 用于对整组数据进行快速运算的标准数学函数(无需编写循环)
  • 用于读写磁盘数据的工具以及用于操作内存映射文件的工具
  • 线性代数、随机数生成以及傅立叶变换功能
  • 用于集成由C、C++、Fortran等语言编写的代码的API

2.2 ndarray


Numpy数组(ndarray)的核心特性

  • 多维性:支持0维(标量)、1维(向量)、2维(矩阵)及更高维数组
  • 同质性:所有元素类型必须一致(通过dtype指定)
  • 高效性:基于连续内存块存储,支持向量化运算(如果有不同数据类型会被强制转换为相同数据类型)
import numpy as np

# 创建数组
a = np.array([1, 2, 3])

# 创建多维数组
b = np.array([[1, 2, 3], [4, 5, 6]])

def getF(a):
    return a, a.ndim, a.dtype

print(getF(a)) # (array([1, 2, 3]), 1, dtype('int64'))
print(getF(b)) # (array([[1, 2, 3],
       				 # [4, 5, 6]]), 2, dtype('int64'))

一、ndarray属性

  • shape 数组的形状:行数和列数(或更高维度的尺寸)
  • ndim 维度数量:数组是几维的(1维、2维、3维等)
  • size 总元素个数:数组中所有元素的总数
  • dtype 元素类型:数组中元素的类型(整数、浮点数等)
  • T 转置:行变列,列变行
  • itemsize 单个元素占用的内存字节数
  • nbytes 数组总内存占用量:size * itemsize
  • flags 内存存储方式:是否连续存储(高级优化)

二、ndarray的创建

  • 基础构造:适用于手动构建小规模数组或复制已有数据
    • np.array()
    • np.copy()
  • 预定义形状填充:用于快速初始化固定形状的数组(如全0占位、全1初始化)
    • np.zeros()
    • np.ones()
    • np.empty()
    • np.full()
  • 基于数值范围生成:生成数值序列,常用于模拟时间序列、坐标网格等
    • np.arange()
    • np.linspace()
    • np.logspace()
  • 特殊矩阵生成:数学运算专用(如线性代数中的单位矩阵)
    • np.eye() 单位矩阵
    • np.diag() 对角矩阵
  • 随机数组生成:模拟实验数据、初始化神经网络权重等场景
    • np.random.rand() 均匀分布
    • np.random.randn() 正态分布
    • np.random.randint() 随机整数
    • 随机种子 np.random.seed()
  • 高级构造方法:处理非结构化数据(如文件、字符串)或通过函数生成复杂数组
    • np.array()
    • np.loadtxt()
    • np.fromfunction()
名称 维度 示例 备注
标量 0维 5, 3.14 单个数字、无行列
向量 1维 [1, 2, 3] 只有行或列(一维数组)
矩阵 2维 [[1, 2], [3, 4]] 严格的行列结构(二维表)
张量 >=3维 [[[1, 2], [3, 4]]] 高阶数组(如RGB图像)

矩阵是一个由 行(row) 和 列(column)排列成的矩阵数组

形状(shape) 这个矩阵有2行3列,记作2 x 3矩阵

元素(entry) 矩阵中的每个数字称为元素
$$
零矩阵 所有元素为0
\begin{bmatrix}
0 & 0\
0 & 0\
\end{bmatrix}
$$

$$
单位矩阵 对角线上为1,其余为0
\begin{bmatrix}
1 & 0\
0 & 1\
\end{bmatrix}
$$

$$
对角矩阵 只有对角线有非0值
\begin{bmatrix}
2 & 0\
0 & 3\
\end{bmatrix}
$$

$$
对称矩阵 A = AT
\begin{bmatrix}
1 & 2\
2 & 3\
\end{bmatrix}
$$

三、ndarray的数据类型

数据类型 说明
bool 布尔类型
int8、uint8
int16、uint16
int32、uint32
int64、uint64
有符号、无符号的8位(1字节)整型
有符号、无符号的16位(2字节)整型
有符号、无符号的32位(4字节)整型
有符号、无符号的64位(8字节)整型
float16
float32
float64
半精度浮点型
单精度浮点型
双精度浮点型
complex64
complex128
用两个32位浮点数表示的复数
用两个64位浮点数表示的复数

四、索引与切片

索引/切片类型 描述/用法
基本索引 通过整数索引直接访问元素。索引从0开始
行/列切片 使用冒号:切片语法选择行或列的子集
连续切片 从起始索引到结束索引按步长切片
使用slice函数 通过slice(start, stop, step)定义切片规则
布尔索引 通过布尔条件筛选满足条件的元素,支持逻辑运算符&、|

五、运算

# 1、算术运算
import numpy as np

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print(a + b) 		# [5 7 9]
print(a - b) 		# [-3 -3 -3]
print(a * b) 		# [ 4 10 18]
print(a / b) 		# [0.25 0.4  0.5 ]
print(a ** b) 	# [  1  32 729]
print(a % b) 		# [1 2 3]
print(a // b) 	# [0 0 0]
print(a ** b) 	# [  1  32 729]
print(a % b) 	# [1 2 3]

# 广播机制 1、获取形状 2、是否可以广播
# 同一维度: 相同
a = np.array([1, 2, 3])
b = np.array([[4], [5], [6]])

'''a
1 2 3
1 2 3
1 2 3
b
4 4 4
5 5 5
6 6 6
'''
print(a + b)
# [[5 6 7]
#  [6 7 8]
#  [7 8 9]]

a = np.array([1, 2, 3])
b = np.array([4, 5])
print(b - a)
# 报错

# 矩阵运算
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
b = np.array([[4, 5, 6], [7, 8, 9], [1, 2, 3]])

print(a @ b)
# [[ 21  27  33]
#  [ 57  72  87]
#  [ 93 117 141]]

2.3 Numpy常用函数


1、基本数学

  • np.sqrt(x)
  • np.exp(x)
  • np.log(x)
  • np.sin(x)
  • np.abs(x)
  • np.power(a, b)
  • np.round(x, n)

2、统计

  • np.sum(x)
  • np.mean(x)
  • np.median(x)
  • np.std(x)
  • np.var(x)
  • np.min(x)/np.max(x)
  • np.percentile(x, q)

3、比较

  • np.greater(a, b)
  • np.less(a, b)
  • np.equal(a, b)
  • np.logical_and(a, b)
  • np.where(condition, x, y)

4、去重

  • np.unique(x)
  • np.in1d(a, b)

5、排序

  • np.sort(x)
  • x.sort()
  • np.argsort(x)
  • np.lexsort(keys)

6、其他

  • np.concatenate((a, b))
  • np.split(x, indices)
  • np.reshape(x, shape)
  • np.copy(x)
  • np.isnan(x)
# 计算指数
print(np.exp(1)) # 2.718281828459045

# 计算自然对数
print(np.log(math.e)) # 1.0

# 计算正弦值、余弦值
print(np.sin(np.pi / 2)) # 1.0
print(np.cos(np.pi / 2)) # 6.123233995736766e-17
print(np.isclose(np.cos(np.pi / 2), 0)) # True

# 计算绝对值
arr = np.array([-1, 1, 2, -3])
print(np.abs(arr)) # [1 1 2 3]

# 计算a的b次幂
print(np.power(arr, 2)) # [1 1 4 9]

# 四舍五入
print(np.round([3.2, 3.7, 4.5, 5.8])) # [3. 4. 4. 6.]

# 向上取整,向下取整
arr = np.array([1.6, 25.1, 81.7])
print(np.ceil(arr)) # [ 2. 26. 82.]
print(np.floor(arr)) # [ 1. 25. 81.]

# 检测缺失值 NaN
print(np.isnan([1, 2, np.nan, 3])) # [False False  True False]

2、统计函数

求和、计算平均值、计算中位数、标准差、方差

查找最大值、最小值

计算分位数、累积和、累积积

arr = np.random.randint(1, 20, 8)
print(arr) # [ 7 14  4 13 15 14 17 17]

# 求和
print(np.sum(arr)) # 101

# 计算平均值
print(np.mean(arr)) # 12.625

# 计算中位数
print(np.median(arr)) # 14.0

# 计算标准差、方差
print(np.std(arr)) # 19.234375
print(np.var(arr)) # 4.3857011982122085

# 计算最大值、最小值 及索引位置
print(np.max(arr), np.argmax(arr)) # 17 6
print(np.min(arr), np.argmin(arr)) # 4 2

# 计算分位数, 50就是中位数,代表百分比
print(np.percentile(arr, 80)) # 16.200000000000003

# 累计和、累积积
print(np.cumsum(arr)) # [  7  21  25  38  53  67  84 101]
print(np.cumprod(arr)) # [        7        98       392      5096     76440   1070160  18192720   309276240]

3、比较函数

比较是否大于、小于、等于

逻辑与、或、非

检查数组中是否有一个True,是否所有的都为True

自定义条件

# 是否大于
print(np.greater([3, 4, 5, 6 ,7], 4)) # [False False  True  True  True]

# 是否小于
print(np.less([3, 4, 5, 6 ,7], 4)) # [ True False False False False]

# 是否等于
print(np.equal([3, 4, 5, 6 ,7], 4)) # [False  True False False False]
print(np.equal([3, 4, 5], [4, 4, 4])) # [False  True False]

# 逻辑与 或 非
print(np.logical_and([0, 0], [1, 1])) # [False False]
print(np.logical_or([0, 0], [1, 1])) # [ True  True]
print(np.logical_not([1, 0])) # [False  True]

# 检查元素是都至少有一个元素为True
print(np.any([0, 1, 0, 1, 1])) # True
# 检查是否全部元素为True
print(np.all([1, 1])) # True

# 自定义条件 
# print(np.where(条件, 符合条件的, 不符合条件的))
arr = np.array([1, 2, 3, 4, 5])
print(np.where(arr > 3, arr, 0)) # [0 0 0 4 5]

# 嵌套
score = np.random.randint(50, 100, 20)
print(score)

print(np.where(
    score < 60, '不及格', np.where(
        score < 80, '良好', '优秀'
    )    
))
# [89 83 76 93 80 84 63 94 84 62 89 75 99 65 51 66 99 65 89 92]
# ['优秀' '优秀' '良好' '优秀' '优秀' '优秀' '良好' '优秀' '优秀' '良好' '优秀' '良好' '优秀' '良好'
# '不及格' '良好' '优秀' '良好' '优秀' '优秀']

# np.select(条件, 返回的结果)
print(np.select([score > 80, (score >= 60) & (score <= 80), score < 60], 
                ['优秀', '良好', '不及格'], 
                default='未知'))
# ['不及格' '优秀' '不及格' '良好' '不及格' '良好' '良好' '优秀' '不及格' '优秀' '良好' '优秀' '良好' '优秀'
# '优秀' '良好' '良好' '良好' '良好' '优秀']

4、排序函数

# sort
np.random.seed(0)
arr = np.random.randint(1, 100, 20)
print(arr) # [45 48 65 68 68 10 84 22 37 88 71 89 89 13 59 66 40 88 47 89]
print(np.sort(arr)) # [10 13 22 37 40 45 47 48 59 65 66 68 68 71 84 88 88 89 89 89]
print(np.argsort(arr)) # [ 5 13  7  8 16  0 18  1 14  2 15  3  4 10  6 17  9 11 12 19]
print(arr) # [45 48 65 68 68 10 84 22 37 88 71 89 89 13 59 66 40 88 47 89]

# 去重
print(np.unique(arr)) # [10 13 22 37 40 45 47 48 59 65 66 68 71 84 88 89]

# 数组的拼接
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
print(arr1 + arr2) # [5 7 9]
print(np.concatenate((arr1, arr2))) # [1 2 3 4 5 6]

# 数组的分割
print(np.split(arr, 4))
# [array([45, 48, 65, 68, 68]), array([10, 84, 22, 37, 88]), array([71, 89, 89, 13, 59]), array([66, 40, 88, 47, 89])]

print(np.split(arr, [6, 12, 18]))
# [array([45, 48, 65, 68, 68, 10]), array([84, 22, 37, 88, 71, 89]), array([89, 13, 59, 66, 40, 88]), array([47, 89])]

# 调整数组的形状
print(np.reshape(arr, [4, 5]))
# [[45 48 65 68 68]
# [10 84 22 37 88]
# [71 89 89 13 59]
# [66 40 88 47 89]]

第三章 Pandas数据处理


3.1 Pandas简介


Pandas是Python数据分析工具链中最核心的库,充当数据读取、清洗、分析、统计、输出的高效工具

Pandas提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据

Pandas是基于NumPy构建的专门为处理表格和混杂数据设计的Python库,核心设计理念包括:

  • 标签化数据结构:提供带标签的轴
  • 灵活处理缺失数据:内置NaN处理机制
  • 智能数据对齐:自动按标签对齐数据
  • 强大IO工具:支持从CSV、Excel、SQL等20+数据源读写
  • 时间序列处理:原生支持日期时间处理和频率转换
特性 Series DataFrame
维度 一维 二维
索引 单索引 行索引 + 列名
数据存储 同质化数据类型 各列可不同数据类型
类比 Excel单列 整张Excel工作表
创建方式 pd.Series([1, 2, 3]) pd.DataFrame({‘col’: [1, 2, 3]})

3.2 核心数据结构 Series


  • Series Index
  • Series Name
  • Series Values

1、创建方法

import pandas as pd

s = pd.Series([1, 2, 3, 4, 5])
print(s)
# 0    1
# 1    2
# 2    3
# 3    4
# 4    5
# dtype: int64

# 自定义索引
s = pd.Series([1, 2, 3, 4, 5], index=['A', 'B', 'C', 'D', 'E'])
print(s)
# A    1
# B    2
# C    3
# D    4
# E    5
# dtype: int64

# 定义name
s = pd.Series([1, 2, 3, 4, 5], index=['A', 'B', 'C', 'D', 'E'], name = '月份')
print(s)
# A    1
# B    2
# C    3
# D    4
# E    5
# Name: 月份, dtype: int64

# 通过字典的方式创建
s = pd.Series({'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5})
print(s)
# a    1
# b    2
# c    3
# d    4
# e    5
# dtype: int64

s1 = pd.Series(s, index=['a', 'c'])
print(s1)
# a    1
# c    3
# dtype: int64

2、属性

属性 说明 属性 说明
index Series的索引对象 loc[] 显式索引,按标签索引或切片
values Series的值 iloc[] 隐式索引,按位置索引或切片
dtype或dtypes Series的元素类型 at[] 使用标签访问单个元素
shape Series的形状 iat[] 使用位置访问单个元素
ndim Series的维度
size Series的元素个数
name Series的名称

3、访问数据

# 访问数据
print(s[1]) # 2
print(s['c']) # 3
print(s[s < 3])
# a    1
# b    2
# dtype: int64

print(s.head()) # 前5行数据
print(s.tail()) # 末尾5行数据

4、常用方法

方法 说明 方法 说明
head() 查看前n行数据,默认5行 max() 最大值
tail() 查看后n行数据,默认5行 var() 方差
isin() 判断元素是否包含在参数集合中 std() 标准差
isna() 判断是否为缺失值(如NaN或None) median() 中位数
sum() 求和,自动忽略缺失值 mode() 众数(可返回多个)
mean() 平均值 qiantile(q) 分位数,q取0~1之间
min() 最小值 describe() 常见统计信息(count、mean、std、min、25%、50%、75%、max)
value_counts() 每个唯一值的出现次数 sort_values() 按值排序
count() 非缺失值数量 replace() 替换值
nunique() 唯一值个数(去重) keys() 返回Series的索引对象
unique() 获取去重后的值数组 sample() 随机抽样
drop_duplicates() 去除重复项 sort_index() 按索引排序
  • 收益率
import pandas as pd
prices = pd.Series([102.3, 103.5, 105.1, 104.8, 106.2, 107.0, 106.5, 108.1, 109.3, 110.2], 
                   index=pd.date_range('2025-01-01', periods=10))

print(prices.pct_change())
# 2025-01-01         NaN
# 2025-01-02    0.011730
# 2025-01-03    0.015459
# 2025-01-04   -0.002854
# 2025-01-05    0.013359
# 2025-01-06    0.007533
# 2025-01-07   -0.004673
# 2025-01-08    0.015023
# 2025-01-09    0.011101
# 2025-01-10    0.008234
# Freq: D, dtype: float64

3.3 核心数据结构 DataFrame


1、创建方法

# 通过series创建
s1 = pd.Series([1, 2, 3, 4, 5])
s2 = pd.Series([6, 7, 8, 9, 10])
df = pd.DataFrame({"第一列": s1, "第二列": s2})
#    第一列  第二列
# 0    1    6
# 1    2    7
# 2    3    8
# 3    4    9
# 4    5   10

# 通过字典来创建
df = pd.DataFrame(
    {
        "name": ['tom', 'jack', 'alice', 'bob', 'allen'],
        "age": [15, 17, 20, 26, 30],
        "score": [60.5, 80, 30.6, 70, 83.5]    
    }, index = [1, 2, 3, 4, 5], columns = ["name", "age", "score"]
)
#     name  age  score
# 1    tom   15   60.5
# 2   jack   17   80.0
# 3  alice   20   30.6
# 4    bob   26   70.0
# 5  allen   30   83.5

2、属性

属性 说明 属性 说明
index DataFrame的行索引 loc[] 显式索引,按行列标签索引或切片
values DataFrame的值 iloc[] 隐式索引,按行列位置索引或切片
dtypes DataFrame的元素类型 at[] 使用行列标签访问单个元素
shape DataFrame的形状 iat[] 使用行列位置访问单个元素
ndim DataFrame的维度 T 行列转置
size DataFrame的元素个数
columns DataFrame的列标签

3、访问数据

# 获取单列数据
print(df['name'])
# 1      tom
# 2     jack
# 3    alice
# 4      bob
# 5    allen
# Name: name, dtype: object

# 获取多列数据
print(df[['name', 'score']])
#     name  score
# 1    tom   60.5
# 2   jack   80.0
# 3  alice   30.6
# 4    bob   70.0
# 5  allen   83.5

# 查看部分数据
print(df.tail(3))
print(df[df.score > 70])
#     name  age  score
# 3  alice   20   30.6
# 4    bob   26   70.0
# 5  allen   30   83.5

#     name  age  score
# 2   jack   17   80.0
# 5  allen   30   83.5

# 随机抽样 df.sample() 默认取一条
print(df.sample(2))
#     name  age  score
# 5  allen   30   83.5
# 2   jack   17   80.0

4、常用方法

方法 说明 方法 说明
head() 查看前n行数据,默认5行 max() 最大值
tail() 查看后n行数据,默认5行 var() 方差
isin() 判断元素是否包含在参数集合中 std() 标准差
isna() 判断是否为缺失值(如NaN或None) median() 中位数
sum() 求和,自动忽略缺失值 mode() 众数(可返回多个)
mean() 平均值 quantile(q) 分位数, q取0~1之间
min() 最小值 describe() 常见统计信息(count、mean、std、min、25%、50%、75%、max)
value_counts() 每个唯一值的出现次数 sort_values() 按值排序
count() 非缺失值数量 replace() 替换值
duplicated() 是否重复 nlargest() 返回某列最大的n条数据
drop_duplicates() 去除重复项 nsmallest() 返回某列最小的n条数据
sample() 随机抽样
replace() 替换值
sort_index() 按索引排序

3.4 数据分析


3.4.1 数据导入导出

# 导入
file_path = '../data/a.csv'

# 手动设定为 gb18030
df = pd.read_csv(file_path, encoding='gb18030')
print(df)
print(type(df))
print(df.tail())
print(df.居民消费价格指数.mean())

# 导出
df = df.tail()
df.to_csv('../data/new.csv')

日期  居民消费价格指数  食品烟酒类居民消费价格指数  衣着类居民消费价格指数  居住类居民消费价格指数  生活用品及服务类居民消费价格指数  交通和通信类居民消费价格指数  教育文化和娱乐类居民消费价格指数  ...  进出口差额当期值(千美元)  进出口差额累计值(千美元)   房地产股票成交量  房地产股票成交金额  房地产股票成交总市值   房地产股票流通市值        房价  Unnamed: 26
0   2022/8/22       NaN            NaN          NaN          NaN               NaN             NaN               NaN  ...            NaN            NaN    7710101   22171554  2373809244  2373809244  57597/57597/1   2022/7/22     101.9          102.5        100.9        100.6             100.8           106.6             101.2  ...    101267263.0    482299580.0   15625022   47609385  2514909793  2514909793  56059/56059/2   2022/6/22     101.8          102.0        100.9        100.8             100.6           106.7             101.5  ...     97940000.0    385440000.0   16592600   50186012  2514909793  2514909793  53552/53552/3   2022/5/22     101.7          101.6        100.8        101.0             100.3           106.1             101.5  ...     78750000.0    290460000.0   42309498  126100275  2481709664  2481709664  50136/50136/4   2022/4/22     101.6          100.8        100.8        101.2             100.0           106.0             101.7  ...     51120000.0    212930000.0  111967542  435194959  3303412863  3303412863  47135/47135/..        ...       ...            ...          ...          ...               ...             ...               ...  ...            ...            ...        ...        ...         ...         ...       ...          ...
75  2022/5/16     102.0          104.7        101.5        101.6             100.6            97.4             101.2  ...     49979506.0    217497631.0   11385855   59587043  4382417065  4382417065  59659/59659/76  2022/4/16     102.3          105.9        101.5        101.4             100.5            97.6             101.2  ...     45557603.0    171041773.0   21244325  104936580  4158316192  4158316192  59076/59076/77  2022/3/16     102.3          106.0        101.5        101.3             100.4            97.4             101.2  ...     29856925.0    125725937.0   20008614   94164575  3950815384  3950815384  58941/58941/78  2022/2/16     102.3          105.8        101.6        101.3             100.3            98.4             100.9  ...     32592484.0     95894192.0    6686454   28775494  3527513736  3527513736  58657/58657/79  2022/1/16     101.8          103.6        101.9        101.4             100.6            98.4             101.7  ...     63286844.0     63286844.0   17630423  103453240  4606517938  4606517938  58993/58993/[80 rows x 27 columns]
<class 'pandas.core.frame.DataFrame'>
           日期  居民消费价格指数  食品烟酒类居民消费价格指数  衣着类居民消费价格指数  居住类居民消费价格指数  生活用品及服务类居民消费价格指数  交通和通信类居民消费价格指数  教育文化和娱乐类居民消费价格指数  ...  进出口差额当期值(千美元)  进出口差额累计值(千美元)  房地产股票成交量  房地产股票成交金额  房地产股票成交总市值   房地产股票流通市值        房价  Unnamed: 26
75  2022/5/16     102.0          104.7        101.5        101.6             100.6            97.4             101.2  ...     49979506.0    217497631.0  11385855   59587043  4382417065  4382417065  59659/59659/76  2022/4/16     102.3          105.9        101.5        101.4             100.5            97.6             101.2  ...     45557603.0    171041773.0  21244325  104936580  4158316192  4158316192  59076/59076/77  2022/3/16     102.3          106.0        101.5        101.3             100.4            97.4             101.2  ...     29856925.0    125725937.0  20008614   94164575  3950815384  3950815384  58941/58941/78  2022/2/16     102.3          105.8        101.6        101.3             100.3            98.4             100.9  ...     32592484.0     95894192.0   6686454   28775494  3527513736  3527513736  58657/58657/79  2022/1/16     101.8          103.6        101.9        101.4             100.6            98.4             101.7  ...     63286844.0     63286844.0  17630423  103453240  4606517938  4606517938  58993/58993/[5 rows x 27 columns]
101.72278481012657

3.4.2 缺失值的处理

# 缺失值处理
s = pd.Series([1, 2, np.nan, None, pd.NA])
print(s)
# 0       1
# 1       2
# 2     NaN
# 3    None
# 4    <NA>
# dtype: object

# 查看是否是缺失值
print(s.isna())
print(s.isnull())
# 0    False
# 1    False
# 2     True
# 3     True
# 4     True
# dtype: bool

df = pd.DataFrame([[1, pd.NA, 2], [2, 3, 5], [None, 4, 6]])
print(df)
#      0     1  2
# 0  1.0  <NA>  2
# 1  2.0     3  5
# 2  NaN     4  6

print(df.isna())
print(df.isnull())
#        0      1      2
# 0  False   True  False
# 1  False  False  False
# 2   True  False  False

print(df.isna().sum()) # 列
# 0    1
# 1    1
# 2    0
# dtype: int64

# 剔除缺失值
print(s.dropna())
# 0    1
# 1    2
# dtype: object

print(df.dropna()) # 剔除一整条记录
print(df.dropna(how = 'all')) # 如果所有值都是缺失值, 删除这一行
print(df.dropna(thresh = 2)) # 如果至少有n个值不是缺失值, 就保留
print(df.dropna(axis = 1)) # 剔除一整列的记录
print(df.dropna(subset = ['第一列'])) # 如果某列有缺失值,则删除这一行

# 填充缺失值
# 使用字典来填充
print(df.fillna({'列名': '值'}).tail())
# 使用统计值来填充 
print(df.fillna(df[['列名']].mean()).tail())
# 用前面的相邻值填充
print(df.ffill().tail())
# 用后面的相邻值填充
print(df.bfill().tail())

3.4.4 重复数据处理

data = {
    "name": ['alice', 'alice', 'bob', 'alice', 'jack', 'bob'],
    "age": [26, 25, 30, 25, 35, 30],
    "city": ['NY', 'NY', 'LA', 'NY', 'SF', 'LA']
}

df = pd.DataFrame(data)
print(df)
#     name  age city
# 0  alice   26   NY
# 1  alice   25   NY
# 2    bob   30   LA
# 3  alice   25   NY
# 4   jack   35   SF
# 5    bob   30   LA

# 一整条记录都是一样的, 标记为重复, 返回True
print(df.duplicated())
# 0    False
# 1    False
# 2    False
# 3     True
# 4    False
# 5     True
dtype: bool

# 去除重复
print(df.drop_duplicates())
#     name  age city
# 0  alice   26   NY
# 1  alice   25   NY
# 2    bob   30   LA
# 4   jack   35   SF

# 根据某个字段去重
print(df.drop_duplicates(subset=['name']))
#     name  age city
# 0  alice   26   NY
# 2    bob   30   LA
# 4   jack   35   SF

3.4.5 数据类型转换

df['age'] = df['age'].astype('int16')
df['gender'] = df['gender'].astype('category')

df['is_male'] = df['gender'].map({'Female': True, 'Male': False})

3.4.6 数据变形

data = {
    'ID': [1, 2],
    'name': ['alice', 'bob'],
    'Math': [90, 85],
    'English': [88, 92],
    'Science': [95, 89]    
}

df = pd.DataFrame(data)
df.T # 行列转置
print(df)

#    ID   name  Math  English  Science
# 0   1  alice    90       88       95
# 1   2    bob    85       92       89

# 宽表转换成长表
df = pd.melt(df, id_vars = ['ID', 'name'], var_name = '科目', value_name = '分数')
df = df.sort_values('name')
print(df)
#    ID   name       科目  分数
# 0   1  alice     Math  90
# 2   1  alice  English  88
# 4   1  alice  Science  95
# 1   2    bob     Math  85
# 3   2    bob  English  92
# 5   2    bob  Science  89

# 长表转换成宽表
df = pd.pivot(df, index = ['ID', 'name'], columns = '科目', values = '分数')
print(df)
# 科目        English  Math  Science
# ID name                         
# 1  alice       88    90       95
# 2  bob         92    85       89

# 分列
df[['first', 'last']] = df['name'].str.split(" ", expand = True)

3.4.7 数据分箱

# 数据分箱 pd.cut(x, bins, labels)
# bins = n, 分成n段区间, 起始值、结束值是所有数据的最大值、最小值
pd.cut(df1['salary'], bins = 2)

# bins = list, 分成n段区间
pd.cut(df1['salary'], bins = [0, 10000, 20000, 30000])
pd.cut(df1['salary'], bins = [0, 10000, 20000, 30000]).value_counts()
pd.cut(df1['salary'], bins = [0, 10000, 20000, 30000], labels = ['低', '中', '高'])

# 等频划分
pd.qcut(df['salary'], 3).value_counts()

3.4.8 时间数据处理

df['datetime'] = pd.to_datetime(df['date'])
df['datetime'].dt.day_name()

df = pd.read_csv('data/weather.csv', parse_dates = ['date'])
df.info()
df['datetime'].dt.day_name()

# 日期数据作为索引
df.set_index('date', inplace=True)
print(df.loc["2025-01" : "2025-05"])

3.4.9 分组聚合

# 分组聚合
# df.groupby('分组的字段')['聚合的字段'].聚合函数()
df.dropna(sub = ['department_id'])
df['department_id'] = df['department_id'].astype('int64')
df.groupby('department_id').groups # 查看分组
df.groupby('department_id').get_group(10) # 查看具体的某个分组数据

第四章 matplotlib 数据可视化


4.1 可视化基础


常见图表

  • 柱状图
  • 折线图
  • 散点图
  • 条形图
  • 饼图
  • 箱型图

数据可视化图表的构成

  • 标题
  • 坐标轴
  • 图形要素
  • 图例
  • 数据标签
工具 说明 优点 缺点
matplotlib Python最基础可视化库 灵活强大、定制性强 代码多、风格基础
seaborn 基于matplotlib的高级接口 风格美观、统计图方便 对简单图略繁琐
pandas plot 快速图表,调用.plot() 快捷、适合EDA 图表样式较少

4.2 Matplotlib


4.2.1 折线图 plot

import matplotlib.pyplot as plt # type: ignore
from matplotlib import rcParams
rcParams['font.family'] = 'STHeiti'

# 创建图表 设置大小
plt.figure(figsize = (10, 5))

# 要绘制的数据
month = ['1月', '2月', '3月', '4月', '5月']
sales = [100, 150, 80, 130, 70]

plt.plot(month, sales, label = '产品A')

# 添加标题
plt.title('2025年销售趋势', color = 'red', fontsize = 20)

# 添加坐标轴的标签
plt.xlabel('月份', fontsize = 10)
plt.ylabel('销售额(万元)', fontsize = 10)

# 添加图例
plt.legend(loc = 'upper left')

# 添加网格线
plt.grid(True, alpha = 0.1, color = 'blue', linestyle = '--')
# plt.grid(axis = 'x')
# plt.grid(axis = 'y')

# 显示图标
plt.show()

##################################################
# 设置y轴范围
plt.ylim(0, 160)

# 在每个数据点上显示数值
for x,y in zip(month, sales):
  print(x, y)
  plt.text(x, y + 1, str(y), ha = 'center', va = 'bottom', fontsize = 10)
  
# 添加样式
plt.plot(month, sales, 
         label = '产品A',
         color = 'orange',
         linewidth = 2,
         linestyle = '--',
         marker = 'o')

4.2.2 条形图 bar

import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'STHeiti'

# 创建图表 设置大小
plt.figure(figsize = (10, 5))

# 要绘制的数据
subjects = ['语文', '数学', '英语', '科学']
scores = [92, 99, 88, 98]

# 绘制柱状图 bar / 条形图 barh
plt.bar(subjects, scores,
        label = 'xxx',
        color = 'orange',
        width = 0.6)

# 添加标题
plt.title('2025年成绩分布', color = 'red', fontsize = 20)

# 添加坐标轴的标签
plt.xlabel('科目', fontsize = 10)
plt.ylabel('分数', fontsize = 10)

# 添加图例
plt.legend(loc = 'upper right')

# 添加网格线
plt.grid(axis = 'y', alpha = 0.1, color = 'blue', linestyle = '--')

# 设置刻度字体大小
plt.xticks(rotation = 0, fontsize = 12)
plt.yticks(rotation = 0, fontsize = 12)

# 设置y轴的范围
plt.ylim(0, 100)

# 在每个数据点上显示数值
for x, y in zip(subjects, scores):
        plt.text(x, y + 1, str(y), ha = 'center', va = 'bottom', fontsize = 10)

# 自动优化排版
plt.tight_layout()

# 显示图标
plt.show()

4.2.3 饼图 pie

import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'STHeiti'

# 创建图表 设置大小
plt.figure(figsize = (10, 5))

# 要绘制的数据
things = ['学习', '娱乐', '运动', '睡觉', '其他']
times = [6, 4, 1, 8, 5]
colors = ['red', 'green', 'blue', 'yellow', 'purple']
explode = [0.1, 0, 0, 0, 0]

# 绘制饼图
plt.pie(times,
        labels = things,
        autopct='%1.1f%%',
        startangle = 90, # 设置起始角度
        colors = colors, # 设置颜色
        wedgeprops = {'width: 0.5'}, # 环形图
        explode = explode, # 设置突出块
        shadow = True # 设置阴影
       )

# 添加标题
plt.title('一天的时间分布', color = 'red', fontsize = 20)

# 自动优化排版
plt.tight_layout()

# 显示图标
plt.show()

4.2.4 散点图 scatter

import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'STHeiti'
import random

# 创建图表 设置大小
plt.figure(figsize = (10, 8))

# 要绘制的数据
x = []
y = []
for i in range(1000):
    tmp = random.uniform(0, 10)
    x.append(tmp)
    y.append(2 * tmp + random.gauss(0, 2))

# 绘制散点图
plt.scatter(x, y,
            color = 'blue',
            alpha = 0.5,
            s = 20,
            label = 'data')


# 添加标题
plt.title('X变量与Y变量的关系', color = 'red', fontsize = 20)

# 添加坐标轴的标签
plt.xlabel('X自变量', fontsize = 10)
plt.ylabel('Y自变量', fontsize = 10)

# 添加图例
plt.legend(loc = 'upper left')

# 添加网格线
plt.grid(True, alpha = 0.1, color = 'blue', linestyle = '--')

# 设置刻度字体大小
plt.xticks(rotation = 0, fontsize = 12)
plt.yticks(rotation = 0, fontsize = 12)

# 设置y轴范围
plt.ylim(0, 30)

# 自动优化排版
plt.tight_layout()

# 显示图标
plt.show()

4.2.5 箱线图 boxplot

import matplotlib.pyplot as plt
from matplotlib import rcParams

rcParams['font.family'] = 'STHeiti'

data = {
    '语文': [82, 85, 88, 70, 90, 76, 84, 83, 95],
    '数学': [75, 80, 79, 93, 88, 82, 87, 89, 92],
    '英语': [70, 72, 68, 65, 78, 80, 85, 90, 95]
}

plt.figure(figsize=(8, 6))
plt.boxplot(data.values(), labels = data.keys())

plt.title("各科成绩分布(箱线图)")
plt.ylabel("分数")
plt.grid(True, axis = 'y', linestyle = '--', alpha = 0.5)
plt.show()
  • 折线图:趋势随时间变化
  • 条形图/柱状图:类别之间对比
  • 饼图:整体组成比例
  • 散点图:两变量相关性
  • 箱线图:数据分布、异常

4.3 Seaborn


import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

plt.rcParams['font.sans-serif'] = ["STHeiti"]
file_path = '../data/a.csv'

# 推荐手动设定为 gb18030
df = pd.read_csv(file_path, encoding='gb18030')
df.dropna(inplace = True)
df.info()

sns.histplot(data = df, x = "房地产股票成交量", kde = True)
plt.show()
1. 导入与基础设置
import seaborn as sns
import matplotlib.pyplot as plt

sns.set_theme(style="whitegrid")  # 设置主题风格
# 常用风格:white, dark, whitegrid, darkgrid, ticks

2. 常用绘图函数
(1)散点图
	sns.scatterplot(data=df, x="col1", y="col2", hue="category", style="type", size="value")
    •	hue:按分类上色
    •	style:按分类改变点样式
    •	size:点的大小
(2)折线图
	sns.lineplot(data=df, x="time", y="value", hue="category", marker="o")
    •	marker:添加点形状
    •	适合画趋势变化
(3)柱状图(类别统计)
	sns.barplot(data=df, x="category", y="value", estimator="mean", ci="sd")
    •	estimator:统计函数(默认均值,可改为 sum、len 等)
    •	ci:置信区间("sd" 表示标准差,None 取消)
(4)计数图(频率统计)
	sns.countplot(data=df, x="category", hue="type")
    •	自动统计每个类别出现次数
(5)直方图 / 密度图
	sns.histplot(data=df, x="value", bins=20, kde=True)
	sns.kdeplot(data=df, x="value", fill=True)
		•	bins:直方图分组数
		•	kde=True:同时绘制核密度曲线
(6)箱线图 / 小提琴图
	sns.boxplot(data=df, x="category", y="value", hue="type")
	sns.violinplot(data=df, x="category", y="value", hue="type", split=True)
		•	split=True:小提琴图中按 hue 分半绘制
(7)热力图
	corr = df.corr()
	sns.heatmap(corr, annot=True, cmap="coolwarm", fmt=".2f")
		•	annot=True:显示数值
		•	fmt:数值格式化
3. 多图布局
		fig, axes = plt.subplots(1, 2, figsize=(12, 5))
		sns.histplot(data=df, x="value", ax=axes[0])
		sns.boxplot(data=df, x="category", y="value", ax=axes[1])
			•	figsize:画布大小
			•	ax:指定绘图位置
4. 配色
		sns.color_palette("pastel")   # 柔和	
		sns.color_palette("deep")     # 默认深色
		sns.color_palette("coolwarm") # 冷暖渐变
	•	可配合 palette 参数使用:
		sns.barplot(data=df, x="category", y="value", palette="coolwarm")
5. 保存图片
		plt.savefig("plot.png", dpi=300, bbox_inches="tight")
			•	dpi:清晰度
			•	bbox_inches="tight":去掉多余空白