ShanTianQi

numpy + pandas + matplotlib

第一章 导论


1.1 介绍


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

数据分析的完整流程

数据分析工具链


第二章 Numpy科学计算


2.1 Numpy介绍


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

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

部分功能如下:


2.2 ndarray


Numpy数组(ndarray)的核心特性

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属性

二、ndarray的创建

名称维度示例备注
标量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、基本数学

2、统计

3、比较

4、去重

5、排序

6、其他

# 计算指数
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库,核心设计理念包括:

特性SeriesDataFrame
维度一维二维
索引单索引行索引 + 列名
数据存储同质化数据类型各列可不同数据类型
类比Excel单列整张Excel工作表
创建方式pd.Series([1, 2, 3])pd.DataFrame({‘col’: [1, 2, 3]})

3.2 核心数据结构 Series


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、属性

属性说明属性说明
indexSeries的索引对象loc[]显式索引,按标签索引或切片
valuesSeries的值iloc[]隐式索引,按位置索引或切片
dtype或dtypesSeries的元素类型at[]使用标签访问单个元素
shapeSeries的形状iat[]使用位置访问单个元素
ndimSeries的维度
sizeSeries的元素个数
nameSeries的名称

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、属性

属性说明属性说明
indexDataFrame的行索引loc[]显式索引,按行列标签索引或切片
valuesDataFrame的值iloc[]隐式索引,按行列位置索引或切片
dtypesDataFrame的元素类型at[]使用行列标签访问单个元素
shapeDataFrame的形状iat[]使用行列位置访问单个元素
ndimDataFrame的维度T行列转置
sizeDataFrame的元素个数
columnsDataFrame的列标签

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 可视化基础


常见图表

数据可视化图表的构成

工具说明优点缺点
matplotlibPython最基础可视化库灵活强大、定制性强代码多、风格基础
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":去掉多余空白

#Python#数据分析#数据可视化#numpy#pandas#matplotlib