文章目录
1、数据分析
-
流程
-
数据收集
-
数据清洗:缺失值、重复数据、错误数据、格式问题
-
数据分析:统计分析、同环比分析
-
数据可视化:折线图(看趋势) 、柱状图(对比) 、饼图(占比)、散点图(相关性)
-
-
技术栈
- Numpy:高性能数值计算(矩阵/向量)
- Pandas:表格数据处理(类似高级Excel)
- Matplotlib:数据可视化(绘图库)
2、Numpy
-
numpy是Python中科学计算的基础包。提供多维数组对象、各种派生对象以及用于对数组进行快速操作的各种方法
-
安装及导入
npm install numpy import numpy as np -
ndarray,一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组
-
ndarray的核心特性
- 多维性:支持 0 维(标量)、1 维(向量)、2 维(矩阵)及更高维(张量)数组
- 同质性:所有元素类型必须一致(通过 dtype 指定)
- 高效性:基于连续内存块存储,支持向量化运算
1)创建
# 1、将列表/元组转换为 ndarray
list1 = [1,2,3]
tuple2 = ('t1','t2')
arr1 = np.array(list1)
arr2 = np.array(tuple2)
print(arr1,arr2)
# 2、创建独立副本(深拷贝)
arr3 = np.copy(arr1)
print(arr3)
# 3、预定义形状填充
arr4 = np.zeros((2,3)) # 全0数组 [[0. 0. 0.]、[0. 0. 0.]]
arr5 = np.ones(3) # 全1数组 [1. 1. 1.]
arr5a = np.ones(3,dtype=int) # 显式指定类型 [1 1 1]
arr6 = np.empty((1,2)) # 未初始化数组,值随机 [[1.03977794e-312 1.06099790e-312]]
arr7 = np.full((1,2),10) # 填充固定值 [[10 10]]
print(arr4,arr5,arr5a,arr6,arr7)
# 4、基于范围生成
arr8 = np.arange(0,10,2) # 等差序列,生成步长固定的序列 [0 2 4 6 8]
arr9 = np.linspace(0,10,5) # 等间隔序列, [ 0. 2.5 5. 7.5 10. ]
print(arr8,arr9)
# 5、随机数组生成
np.random.seed(10) # 设置随机数生成器种子,参数可以是任意整数,保证重复执行会生成相同的结果
arr10 = np.random.rand(2,2) # 生成 [0,1) 均匀分布的随机数 [[0.77132064 0.02075195] [0.63364823 0.74880388]]
arr11 = np.random.randint(1,100,(2,3)) # 生成指定范围内的随机整数 [1,10) 的整数 :[[90 94 30] [ 9 74 1]]
arr12 = np.random.uniform(2,3,(1,2)) #从低位(包含)到高位(不包含)上均匀分布的随机浮点数填充 [[2.26360285 2.15037787]]
print(arr10,arr11,arr12)
2)数据类型
arr1 = np.array([False,True]) # bool
arr2 = np.array([1,2]) # 默认int64
arr3 = np.array([1,2],dtype=np.int32) # 指定类型 节省空间
arr4 = np.array([1.1,2.1]) #默认float64
arr5 = np.array([1,2],dtype=np.float32) # 指定类型 节省空间
print(arr1.dtype,arr2.dtype,arr3.dtype,arr4.dtype,arr5.dtype) # bool int64 int32 float64 float32
3)索引和切片
# 二维
arr1 = np.arange(1,10,1).reshape((3,3)) # [[1 2 3] [4 5 6] [7 8 9]]
print(arr1[1,2]) # 6 从0开始,访问第2行第三列上的元素
print(arr1[:,1]) # [2 5 8] 所有行的第2列上的元素
print(arr1[::2,::2]) # [[1 3] [7 9]] # 隔行隔列取样
# 一维
arr2 = np.arange(1,10,1)
print(arr2[2:8:3]) # [3 6] 从索引2开始到索引8(不包括),步长3
print(arr2[3:]) # [4 5 6 7 8 9]
print(arr2[slice(2,8,3)]) # [3 6]
# 布尔索引
print(arr1[arr1>5]) # 结果为一维 [6 7 8 9]
print(arr2[(arr2 % 2 == 1) & (arr2<8)]) # [1 3 5 7]
arr2[arr2 % 2 == 1] = -1 # 将奇数替换为-1
print(arr2) # [-1 2 -1 4 -1 6 -1 8 -1]
4)矢量运算和广播
-
矢量化运算 Vectorization
-
用数组级别的操作替代显式循环,利用底层优化(如 SIMD 指令)加速计算
-
避免 Python 的 for 循环,直接对整个数组进行数学运算(如 a + b)
-
要求参与运算的数组形状完全相同(否则会报错或触发广播机制)
-
-
广播机制 Broadcasting
-
当数组形状不完全相同时,NumPy 会尝试自动扩展较小的数组,使其与较大的数组形状兼容
-
允许不同形状的数组进行运算(如标量与数组、行向量与列向量等)
-
广播机制扩展了矢量化运算的适用范围
-
# 矢量化运算,不用编写循环即可执行批量运算,加速运算
arr1 = np.array([1,2,3])
# 数组与标量的算术运算会将标量值传播到各个元素
print(arr1 + 2) # [3 4 5]
# 大小相等的数组之间的任何算术运算都会将运算应用到元素级。
arr2 = np.array([4,5,7])
print(arr1 + arr2) # [ 5 7 10]
#不同大小的数组之间的运算叫做广播
# 广播机制是 NumPy 中一个强大的特性,它允许在不同形状的数组之间进行元素级运算。广播机制的规则如下:
# 规则1:如果数组的维度数不相同,那么小维度数组的形状将会在最左边补1。
arr3 = np.array([1,2,3]) # 形状为 (3,) 补1后 形状为 (1,3) 即 [[1,2,3]]
arr4 = np.array([[1,2,3],[4,5,6]]) # 形状为 (2,3)
print(arr3+arr4) # [[2 4 6] [5 7 9]]
# 规则2:如果数组的形状在任何一个维度上都不匹配,那么数组的形状会沿着维度大小(元素个数)为1的维度开始扩展 ,(维度必须是1开始)直到所有维度都一样, 以匹配另一个数组的形状。
arr5 = np.array([1,2,3]) # 形状为 (3,) 扩展为 [[1,2,3] [1,2,3] [1,2,3]]
arr6 = np.array([[1],[2]]) # 形状为 (2,1) 扩展为 [[1,1,1],[2,2,2]]
print(arr5+arr6) # [[2 3 4] [3 4 5]]
# 规则3:如果数组的形状在任何一个维度上都不匹配,并且没有任何一个维度大小等于1,那么会引发异常。
arr7 = np.array([1,2])
# print(arr3+arr7) # ValueError: operands could not be broadcast together with shapes (3,) (2,)
arr8 = np.array([[1,2],[2,3]])
# print(arr3 + arr8) # ValueError: operands could not be broadcast together with shapes (3,) (2,2)
5)属性
- shape:数组的形状(行数和列数)
- ndim:数组的维度
- size:数组中所有元素的总数
- dtype:数组中元素的类型
# 一维数组
arr1 = np.array([1,2,3.0]) # 包含浮点数,自动提升为浮点类型
print(arr1.shape,arr1.ndim,arr1.size,arr1.dtype) # (3,) 1 3 float64
print(arr1.T) # [1. 2. 3.]
# 二维数组
arr2 = np.array([[1,2,3],[3.0,4,5]])
print(arr2.shape,arr2.ndim,arr2.size,arr2.dtype) # (2, 3) 2 6 float64
print(arr2.T) # [[1. 3.]、[2. 4.]、[3. 5.]]
6)常用方法
# 1、基本数学
print('-------------1、基本数学')
arr1 = np.array([1,2,4,3.45,3.46])
print(np.sqrt(arr1)) # 计算平方根
print(np.abs(arr1)) # 计算绝对值
print(np.power(arr1,2)) #计算 a 的 b 次幂
print(np.round(arr1,1)) # 四舍五入(保留 n 位小数) 注意 # [1. 2. 4. 3.4 3.5]
print(np.ceil(arr1)) # 向上取整 [1. 2. 4. 4. 4.]
print(np.floor(arr1)) # 向下取整 [1. 2. 4. 3. 3.]
print(np.rint(arr1)) # 四舍五入到最近的整数;当需要舍入的数字恰好是 5 时,会看 5前面的数字,如果是偶数则直接舍去 5,如果是奇数则进位。[1. 2. 4. 3. 3.]
print(np.multiply(arr1, 2)) # 元素级乘法(等价于 a * b)
print(np.isnan(arr1)) # 检测 NaN 值 [False False False False False]
# 2、统计
print('-------------2、统计')
arr2 = np.array([10,20,30,40,50,30])
print(np.sum(arr2)) # 求和 # 180
print(np.mean(arr2)) # 计算均值 #30.0
print(np.min(arr2),np.max(arr2)) # 查找最小值/最大值 # 10 50
print(np.argmin(arr2),np.argmax(arr2)) # 查找最小值/最大值 的索引 # 0 4
print(np.size(arr2)) # 元素个数 6
print(np.count_nonzero(arr2)) # 非零元素的数量 6
# 众数:出现频率最高的值;可能有多个
import scipy
print(scipy.stats.mode(arr2)) # 需SciPy支持 ModeResult(mode=np.int64(30), count=np.int64(2))
# 中位数:将所有值排序后位于中间位置的那个值
# # 先从小到大排序,如果元素个数为奇数,则中间数就是众数;如果为偶数,则中间两个数的平均数即为众数
print(np.median(arr2)) # 计算中位数 # 30.0
# 方差越小,代表这组数据越稳定,方差越大,代表这组数据越不稳定
# 方差=((均值-元素1)**2 + (均值-元素2)**2 ...)/元素个数
print(sum([(np.mean(arr2)-i)**2 for i in arr2])/arr2.size) # 166.66666666666666
print(np.var(arr2)) # 计算方差 #166.66666666666666
# 标准差越小,表明数据越聚集;标准差越大,表明数据越离散
# 标准差=对方差开平方
print(np.sqrt(np.var(arr2))) # 12.909944487358056
print(np.std(arr2)) # 计算标准差 # 12.909944487358056
# 分位数
# 手工计算:先排序 [10,20,30,30,40,50]
# 可以看作是5段 5*0.3 = 1.5
# 1位置上的数是20 + (30-20)*(1.5-1)= 25
print(np.percentile(arr2, 30)) # 计算百分位数(q: 0~100) #25.0
print(np.quantile(arr2,0.3)) # 分位数 # 25.0
print(np.cumsum(arr2)) # 累计和 [ 10 30 60 100 150 180]
print(np.cumprod(arr2)) # 累计积 [ 10 200 6000 240000 12000000 360000000]
# 多维数组在计算时默认计算全部维度,可以使用axis参数指定按某一维度为轴心统计,axis=0按列统计、axis=1按行统计。
arr2 = np.array([[1,2,3],[4,5,6]])
print(np.sum(arr2))
print(np.sum(arr2,axis=1)) # 按行求和 [ 6 15]
print(np.sum(arr2,axis=0)) # 按列求和 [5 7 9]
# 3、比较
print('-------------3、比较')
arr3 = np.array([1,2,0])
arr4 = np.array([1,3,5])
print(np.greater(arr3, arr4)) # [False False False]
print(np.less(arr3, arr4)) # [False True True]
print(np.equal(arr3, arr4)) # [ True False False]
print(np.logical_and(arr3, arr4)) # [ True True False] 逻辑与(逐元素) (0 为 False,非零为 True)
print(np.logical_or(arr3,arr4)) # [ True True True]
print(np.logical_not(arr3,arr4)) # [0 0 1]
print(np.all(arr3)) # False 检查数组中是否 所有元素 为 True,np.all([]) 返回 True
print(np.any(arr4)) # True 检查数组中是否 至少有一个元素 为 True,np.any([]) 返回 False
print(np.where(arr3, 11, 22)) #[11 11 22] 如果为元素为True,则用11替换,否则用22替换
# 4、排序
print('-------------4、排序')
arr5 = np.array([[3,7,2],[1,10,4]])
print(np.sort(arr5)) # 返回排序后的副本 [[ 2 3 7] [ 1 4 10]]
print(np.argsort(arr5)) # 返回排序后的索引 [[2 0 1] [0 2 1]]
print(arr5.sort()) # 修改原数组 None
print(arr5) # [[ 2 3 7] [ 1 4 10]]
print(np.sort(arr5,axis=0)) # 列方向排序 [[ 1 3 7] [ 2 4 10]]
# 5、其他
print('-------------5、其他')
arr6 = np.array([3,7,2,4,7,6])
print(np.unique(arr6)) # 返回唯一值并排序 [2 3 4 6 7]
a,b = np.unique(arr6,return_counts=True)
print(a) # [1 2 3 4] 唯一值并排序 # [2 3 4 6 7]
print(b) # [2 2 2 1] 每个唯一值出现的次数 [1 1 1 1 2]
print(np.isin(arr6, [1,2,4])) # 检查 a 的元素是否在 b 中存在 [False False True True False False]
print(np.split(arr6, [2,4])) # 分割数组 [array([3, 7]), array([2, 4]), array([7, 6])]
print(np.copy(arr6)) # 创建数组的深拷贝 [3 7 2 4 7 6]
# 形状变化
print(np.reshape(arr6, (2,3))) # 一维变二维 [[3 7 2] [4 7 6]]
print(arr6.flatten()) #将二维展平为一维数组 [3 7 2 4 7 6]
# 拼接
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
print(np.concatenate((arr1,arr2))) #水平拼接为 [1, 2, 3, 4, 5, 6]
print(np.vstack((arr1,arr2))) #垂直拼接为 [[1, 2, 3], [4, 5, 6]]
# 缺失值
arr1 = np.array([1, np.nan, 3, np.nan, 5])
print(np.isnan(arr1)) # 检测缺失值NaN [False True False True False]
print(np.sum(~np.isnan(arr1))) # 计算非缺失值数量 3
arr1[np.isnan(arr1)] = 0 #替换缺失值
print(arr1) # [1. 0. 3. 0. 5.]
3、Pandas
-
Pandas 是 Python 数据分析工具链中最核心的库,充当数据读取、清洗、分析、统计、输出的高效工具,特别适用于处理结构化数据,如表格型数据
-
pandas兼具numpy高性能的数组计算功能以及电子表格和关系型数据库(如SQL)灵活的数据处理功能。它提供了复杂精细的索引功能,能更加便捷地完成重塑、切片和切块、聚合以及选取数据子集等操作
-
特点
- 标签化数据结构:提供带标签的轴(行索引和列名)
- 智能数据对齐:自动按标签对齐数据
- 灵活处理缺失数据:内置NaN处理机制
- 强大IO工具:支持从CSV、Excel、SQL等20+数据源读写
- 时间序列处理:原生支持日期时间处理和频率转换
-
Pandas 基于 Numpy,并提供了 2 大核心数据结构
- Series:一维带有标签的数组
- DataFrame:二维表格结构,可看作多个 Series 的组合
-
安装及导入
pip install pandas import pandas as pd
1)Series
-
类似于 NumPy 一维数组,但增加了 “标签”,可以理解为一维标签化数组
-
特点
- 一维数组:Series 中的每个元素都有一个对应的索引值
-
索引: 可以通过位置索引(从0开始)或自定义标签索引访问元素
-
数据类型: Series 可以容纳不同数据类型的元素,包括整数、浮点数、字符串、Python 对象等
-
大小不变性:Series 的大小在创建后是不变的,但可以通过某些操作(如 append 或 delete)来改变
-
操作:Series 支持各种操作,如数学运算、统计分析、字符串处理等
-
缺失数据:Series 可以包含缺失数据,Pandas 使用NaN(Not a Number)来表示缺失或无值
-
自动对齐:当对多个 Series 进行运算时,Pandas 会自动根据索引对齐数据,这使得数据处理更加高效
1.1)创建
# 1、通过列表创建
list1 = ['a','b',1]
s1 = pd.Series(list1)
print(s1)
'''
索引在左边,值在右边。没有为数据指定索引,会自动创建一个0到N-1(N为数据的长度)的整数型索引
0 aa
1 b
2 1
dtype: object
'''
# 指定索引(Index)、名称(Name)
s2 = pd.Series([30,10,20],index=['周一','周二','周三'],name='周')
print(s2)
'''
周一 30
周二 10
周三 20
Name: 周, dtype: int64
'''
# name作用:如果将一个 Series 转换成 DataFrame 或 导出成csv等格式时,name 会自动成为列名
print(s2.to_frame())
'''
周
周一 30
周二 10
周三 20
'''
# 2、通过字典创建
dict1 = {'周一':100,'周二':300}
s3 = pd.Series(dict1)
print(s3)
'''
周一 100
周二 300
dtype: int64
'''
1.2)访问
s = pd.Series([1,2,3,4,5],index=['a','b','c','d','e'])
# 1、位置索引
print(s.iloc[0]) # 通过整数位置访问(从0开始) 1
print(s.iloc[1:2]) # 位置切片(左闭右开) 返回的是Series
# 2、标签索引
print(s.loc['a']) # 通过索引标签访问 1
print(s.loc[['a','b']]) # 通过标签列表访问,返回的是Series
# 3、直接索引
#print(s[0]) # 将来会废弃,因为0无法确定是位置还是标签
print(s['a']) #类似loc(优先标签索引) 1
# 4、布尔索引
print(s[s > 3]) #通过布尔条件筛选,返回Series
print(s[~(s > 3)]) #取反条件,返回Series
# 5、函数访问
print(s.at['a']) # 类似loc但效率更高 1
print(s.iat[0]) # 类似iloc但效率更高 1
# 6、头部/尾部
print(s.head(3)) # 访问前N行(默认5) 返回Series
print(s.tail(2)) # 访问后N行(默认5) 返回Series
1.3)运算
s1 = pd.Series([1,2,3])
s2 = pd.Series([2,3,4])
print(s1+s2) # 对应位置相加 返回Series
print(s1*2) # 逐个元素相乘 返回Series
1.4)属性
s = pd.Series([1,2,3,4,5],index=['a','b','c','d','e'])
print(s.index) # Series的索引对象 Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
print(s.values) # Series的值 [1 2 3 4 5]
print(s.dtype,s.dtypes) # Series的元素类型
print(s.shape) # 形状 (5,)
print(s.ndim) # 维度 1
print(s.size) # 元素个数 5
print(s.name) # None
1.5)方法
s = pd.Series([1,2,3,4,5,1,2])
print(s.isin([1, 2])) # 判断元素是否包含在参数集合中
print(s.isna()) # 判断是否为缺失值(如 NaN 或 None)
print(s.sum()) # 求和,自动忽略缺失值
print(s.mean())
print(s.min(),s.max())
print(a.idxmax(), a.idxmin()) # 最大值/最小值的索引
print(s.var(),s.std()) # 方差 标准差
print(s.median()) # 中位数
print(s.mode()) # 众数(可能有多个) 返回Series
# 默认 interpolation='linear'
# 算法:排序后,看作为len-1=6段, 6*0.3 = 1.8,分为1和0.8
# 索引1上是1, 1 + (2-1)*0.8 = 1.8
print(s.quantile(0.3)) #分位数,q 取 0~1 之间 1.8
# interpolation="midpoint" 采用两个数据点的均值作为结果
# 插值方法:当计算分位数时,若位置不是整数,即分位数位于两个数据点之间时,就需要借助插值方法来确定分位数值
# 算法:(len-1)×0.3=1.8。这意味着 0.3 分位数处于第2个数据点(值为1)和第3个数据点(值为 2)之间
# 使用 "midpoint" 插值方法,分位数值就是这两个数据点的平均值,即 (1+2)÷2=1.5
print(s.quantile(0.3,interpolation="midpoint")) #分位数,q 取 0~1 之间
print(s.describe()) # 常见统计信息
print(s.count()) # 非缺失值数量 7
print(s.nunique()) # 唯一值个数(去重) 5
print(s.unique()) # 去重后的值数组 [1 2 3 4 5]
print(s.value_counts()) # 每个唯一值的出现次数 返回Series
print(s.drop_duplicates()) # 去除重复项 返回Series
print(s.sample(2)) # 随机抽样2个元素 返回Series
print(s.sort_index()) # 按索引排序 返回Series
print(s.sort_values(ascending=False)) # 按值排序 降序 返回Series
print(s.replace({3:30,4:40})) # 替换 返回Series
print(s.to_frame()) # 将 Series 转为 DataFrame
print(s.equals(pd.Series([1,2,3]))) # 判断两个 Series 是否完全相等 False
print(s.keys()) # 返回 Series 的索引对象 RangeIndex(start=0, stop=7, step=1)
print(s.items()) # 返回索引和值的迭代器 <zip object at 0x0000020DE4F72100>
print(s.hist()) # 绘制直方图(需安装 matplotlib)
a = pd.Series([1, 2, 5, 2])
''' diff 算每两天的差异
0 NaN
1 1.0
2 3.0
3 -3.0
dtype: float64
'''
print(a.diff())
''' nlargest 最大的两个
2 3.0
3 3.0
dtype: float64
'''
print(a.diff().abs().nlargest(2))
''' pct_change 后一个数对前一个数的增长率=(n+1)/n-1
0 NaN
1 1.0
2 1.5
3 -0.6
dtype: float64
'''
print(a.pct_change())
sales = pd.Series([2, 4, 5, 6, 5, 7], index=pd.date_range('2025-01-01', periods=6, freq='ME'))
''' resample 重新采样:专用于时间序列数据的重采样,可实现不同频率的转换
2025-03-31 3.666667
2025-06-30 6.000000
Freq: QE-DEC, dtype: float64
'''
print(sales.resample('QE').mean())
# rolling 窗口函数, 找出连续增长超过1个月的月份
print(sales[(sales.pct_change() > 0).rolling(
2).sum() > 1].index.tolist()) # [Timestamp('2025-03-31 00:00:00'), Timestamp('2025-04-30 00:00:00')]
2)DataFrame
- 多行多列表格数据,类似于Excel表格或SQL查询结果
- 它是一个二维表格结构,具有行索引(index)和列标签(columns)
2.1)创建
# 1、通过Series
s1 = pd.Series(['张三','李四'])
s2 = pd.Series(['18','19'])
df = pd.DataFrame({'name':s1,'age':s2})
print(df)
# 2、通过字典 指定列的顺序和行索引
df = pd.DataFrame({'name':['王五','赵六'],'age':[20,21]},columns=['age','name'],index=[1,2])
print(df)
2.2)访问
import pandas as pd
df = pd.DataFrame({'id':[101,102,103],'name':['王五','赵六','张三'],'age':[20,21,22]}
,columns=['id','age','name'],index=['a','b','c'])
# 列选择
print(df['name']) # 选择单列(返回Series)
print(df.name)
print(df[['name','age']]) #选择多列(返回DataFrame)
# 行选择
print(df.loc['b']) # 通过行标签选择单行(返回Series)
print(df.loc[['a','c']]) # 通过行标签选择多行 返回DataFrame
print(df.loc['b':'c']) # 通过标签切片选择多行(闭区间) 返回DataFrame
print(df.iloc[0]) # 通过行位置选择单行(从0开始) 返回Series
print(df.iloc[-1]) # 最后一行
print(df.iloc[0:2]) # 通过位置切片选择多行(左闭右开) DataFrame
# 行+列 选择
print(df.loc['a', 'name']) # 通过标签选择行和列 返回单个值
print(df.loc['a':'b', 'name']) # 返回Series
print(df.loc['a':'b', ['age','name']]) # 返回DataFrame
print(df.iloc[0,2 ]) # 通过位置选择行和列 返回单个值
print(df.iloc[0:2, 1]) # 返回Series
print(df.iloc[0:2, [1,2]]) # # 返回DataFrame
# 条件筛选
print(df[df['age'] > 21]) # DataFrame
print(df.query("age > 20 & id < 103")) # DataFrame
# 快速访问单个值
print(df.at['a', 'name']) # 快速访问单个值(标签索引,高效)
print(df.iat[0, 2]) # 快速访问单个值(位置索引,高效)
# 头部/尾部
print(df.head(1)) # 返回前n行(默认5) DataFrame
print(df.tail(1)) # 返回后n行(默认5) DataFrame
2.3)运算
df = pd.DataFrame({'id':[101,102],'name':['zhang1','zhang2'],'age':[31,21]}
,columns=['id','age','name'],index=['a','b'])
print(df*2) # a 202 62 zhang1zhang1
df1 = pd.DataFrame({'id':[105,106],'name':['li1','li2'],'age':[18,28]}
,columns=['id','age','name'],index=['a','c'])
print(df+df1) # 行索引一致则相加 ,否则结果为NaN
2.4)属性
df = pd.DataFrame({'id':[101,102,103],'name':['王五','赵六','张三'],'age':[20,21,22]}
,columns=['id','age','name'],index=['a','b','c'])
print(df.index) # 行索引 Index(['a', 'b', 'c'], dtype='object')
print(df.columns) # 列标签 Index(['id', 'age', 'name'], dtype='object')
print(df.values) # [[101 20 '王五'] [102 21 '赵六'] [103 22 '张三']]
print(df.ndim) # 维度 2
print(df.shape) # 形状 (3, 3)
print(df.size) # 元素个数 9
print(df.dtypes) # 列类型
2.5)方法
import pandas as pd
df = pd.DataFrame({'id':[101,102,103,104],'name':['zhang1','zhang2','zhang3','zhang4'],'age':[31,21,18,31]}
,columns=['id','age','name'],index=['a','b','c','d'])
print(df.isin([21,'张三',101]))
print(df.isna())
print(df.sum()) # 默认对每列求和或拼接,返回Series(行标签是列名)
print(df[['id','age']].sum(axis=1)) # 指定axis=1 则对每行进行求和
# 针对某列df['age'] 或多列 df[['a','b']]
print(df.age.sum(),df.age.mean(),df.age.max(),df.age.min())
print(df.age.var(),df.age.std()) # 方差 标准差
print(df.age.median()) # 中位数
print(df.age.mode()) # 众数 返回Series
print(df.age.quantile(0.5)) # 指定位置的分位数
print(df.describe()) # 常见统计信息
print(df.info()) # 基本信息:类型、行索引总数、列及类型、占用内存
print(df.value_counts()) # 每行的个数 返回DataFrame
print(df.count()) # 每列非空元素的个数 返回Series(行标签是列名)
print(df.duplicated()) # 是否有重复行
print(df.duplicated(subset='age')) # 是否有重复行(只看指定列的值)
print(df.drop_duplicates(subset='age')) # 去重
print(df.sample(2)) # 随机采样n行,默认1行
print(df.replace(31,33)) # 用指定值代替原有值
# 行 index 1 ;列 columns 0
print(df.sort_index(ascending=False).cummax(axis=0)) # 累计最大值
print(df.cummin(axis=0)) # 累计最小值
print(df.cumsum()) # 累计和
print(df.age.cumprod()) # 累计积
# 一阶差分,对序列中的元素进行差分运算,也就是用当前元素减去前一个元素得到差值
# periods:默认为 1。表示要向前或向后移动的周期数,用于计算差值。正数表示向前移动,负数表示向后移动。
# axis:默认值为 0。指定计算的轴方向。0 或 'index' 表示按列计算,1 或 'columns' 表示按行计算,
print(df[['id','age']].diff(axis='index'))
print(df.sort_index(ascending=False)) # 按行索引排序
print(df.sort_values(by='age')) # 按某列的值排序,可传入列表来按多列排序,
print(df.nlargest(n=2,columns='age')) # 返回某列最大的n条数据
print(df.nsmallest(n=2,columns='age')) # 返回某列最小的n条数据
# 将id或date设置为索引及还原
print(df.set_index('id')) #设置索引 指定某列作为新索引 DataFrame
print(df.reset_index()) #重置索引(原索引变为列) DataFrame
# 获取某列最大值的两种方式
print(df.loc[df['age'].idxmax()]) # 返回Series,如果有多行,则只返回一行 idxmax 返回最大值的行索引,如果指定了标签则返回标签
print(df[df['age']==df['age'].max()]) # 返回DataFrame,可能有多行
3)导入导出数据
import pandas as pd
df = pd.DataFrame({'id':[101,102],'name':['zhang1','zhang2'],'age':[31,21]}
,columns=['id','age','name'],index=['a','b'])
print(df)
# 导出
# 1、to_csv() 保存为csv文件,数据之间以逗号分隔,可通过sep参数指定分隔符。可通过index参数设置是否保存行标签,可通过header参数设置是否保存列标签
# df.to_csv('a.csv',index=False)
# 2、to_excel() 保存为Excel文件,需安装openpyxl包
# df.to_excel('a.xlsx')
# 3、to_clipboard() 保存到剪切板
# df.to_clipboard()
# 4、to_dict() 保存为字典
# print(df.to_dict()) # {'id': {'a': 101, 'b': 102}, 'age': {'a': 31, 'b': 21}, 'name': {'a': 'zhang1', 'b': 'zhang2'}}
# 5、to_json() 保存为JSON
# print(df.to_json()) # {"id":{"a":101,"b":102},"age":{"a":31,"b":21},"name":{"a":"zhang1","b":"zhang2"}}
# df.to_json('a.json')
# 6、to_html() 保存为HTML格式
# df.to_html('a.html')
# 7、to_pickle() 保存成二进制文件,后续使用效率高。适合保存中间结果,或频繁访问的数据。文件的扩展名可以是.p、.pkl、.pickle。
df.to_pickle('a.pkl')
# 8、to_sql() 保存到数据库
# 导入
# 可以通过keep_default_na参数设置是否将空白值设置为缺失值
# 可通过na_values参数将指定值设置为缺失值。
# 可通过index_col参数指定行索引。
#df = pd.read_csv('a.csv') # 可通过sep参数指定分隔符,
# df = pd.read_excel('a.xlsx',index_col=0) # 加载Excel格式的数据
# df = pd.read_clipboard() # 加载剪切板中的数据。
# df = pd.read_html('a.html',index_col=0)[0] # 加载HTML格式的数据.需安装lxml. 返回的是list
# df = pd.read_json('a.json') # 加载JSON格式的数据。
df = pd.read_pickle('a.pkl') # 架子啊pickle格式数据
# read_sql() 加载数据库中的数据。
print(df,type(df))
4)数据的清洗和预处理
import pandas as pd
import numpy as np
# 1. 缺失值处理 检测、删除和填充缺失值的方法 isna() isnull(), dropna(), fillna()
# pandas使用浮点值NaN(Not a Number)表示未定义或无效的数值,使用NA(Not Available)表示缺失值。
df = pd.DataFrame({'id':[101,102,103,104,None],'name':['zhang3','li4',pd.NA,'wang5',None],'age':[18,20,30,np.nan,None]})
print(df)
# df.isna() df.isnull() df.notna() df.notnull()
print(df.isna()) # # 返回布尔矩阵,标记缺失值(是NaN、None、NA)
# print(df.isnull()) # 与isna效果一样
print(df.isna().sum()) # 每列缺失值数量统计
# 删除缺失值
print(df.dropna()) # 删除包含缺失值的行(默认)无法从DataFrame中单独剔除一个值,只能剔除缺失值所在的整行或整列,默认整行。返回删除后的值
print(df.dropna(axis=1)) # 删除包含缺失值的列
print(df.dropna(subset=['name'])) # 仅删除指定列的缺失值行
# how或thresh参数可以设置剔除行或列缺失值的数量阈值
print(df.dropna(how='all')) # 只需要剔除全部是缺失值的行或列
print(df.dropna(thresh=2)) # 如果至少有2个值不是缺失值,则保留这一行
# 填充缺失值
print(df.fillna(0)) # 用固定值填充
print(df.ffill()) # 用前一个非缺失值填充(向前填充)
print(df.bfill()) # 用后一个非缺失值填充(向后填充)
print(df)
# 2. 重复数据处理 识别和删除重复行 duplicated(), drop_duplicates(), 按列去重, 保留首次/最后一次出现
df = pd.DataFrame({'id':[101,102,103,103],'name':['zhang3','li4','wang5','wang5'],'age':[20,20,30,30]})
print(df)
print(df.duplicated()) # 检测重复行 返回布尔Series(False表示首次出现,True表示重复)
print(df.drop_duplicates()) # 删除重复行 保留首次出现的行(默认检查所有列)
print(df.drop_duplicates(subset=['age'])) # 仅根据指定列去重
print(df.drop_duplicates(keep='last')) # keep='last' 保留最后一次出现的行 ;keep=False 删除所有重复
# 3. 数据类型转换 强制类型转换、日期/分类数据处理 astype(), to_datetime(), 分类数据优化, 数值格式化
df = pd.DataFrame({'id':[101,102,103,104],'name':['zhang3','li4','wang5','zhao6'],'sex':['男','女','未知','男']
,'birth':['20010101','20020202','20030303','20040404']
,'salary':[100.123,200,300,None]})
print(df.dtypes) # 显示每列的数据类型 object通常为字符串或混合类型
df['birth'] = pd.to_datetime(df['birth']) # 转换日期:返回datetime64类型的Series
df['salary'] = df['salary'].astype('float32').round(2) # 将列转换为指定类型 #round 保留2位小数
df['sex'] = df['sex'].astype('category') # 将列转为分类类型(节省内存,提高性能)• 加速groupby、sort等操作
df['id'] = df['id'].apply(lambda x : x+10) # 使用apply实现复杂转换
print(df.dtypes) #
print(df)
# 4. 数据重塑与变形 行列转置、宽表长表转换、分列操作 T转置, melt(), pivot(), str.split()分列
df = pd.DataFrame({'id':[101,102,103,104],'name':['zhang-3','li-4','wang-5','zhao-6'],'sex':['男','女','未知','男']
,'math_score':[1,2,3,4],'english_score':[11,22,33,44]})
print(df)
print(df.T) # 行列转置
a = pd.melt(df, id_vars=['id','name','sex'], var_name='科目', value_name='分数') # 宽表转长表,将多列合并为键值对形式(默认名为variable和value列)
print(a)
print(a.pivot(index=['id','name','sex'], columns=['科目'], values='分数')) # 长表转宽表,将长表转换为宽表(类似Excel数据透视) 以ID为索引,variable为列,value为值
df[['first_name','last_name']] = df['name'].str.split('-', expand=True) # 按分隔符拆分字符串为多列
print(df)
# 5. 文本数据处理 字符串清洗、正则提取、大小写转换 str.lower(), str.replace(), str.extract(), 空格处理
df = pd.DataFrame({'id':[101,102,103,104],'name':['ZHANG-3',' li- 4 ','wang-5','zhao-6']
,'email':['zhang@123.com','li@126.com','wang@qq.com','zhao@163.com']})
print(df)
df['name'] = df['name'].str.lower().str.strip() # 字符串大小写转换/去除两端空格
df['name'] = df['name'].str.replace('zhao-6', 'zhao-7') # 替换文本
df['last_name'] = df['name'].str.extract(r'(\d+)') # 正则表达式提取
df['email'] = df['email'].str.extract(r'@(.+)') # 正则表达式提取
print(df['name'].str.contains('a')) # 字符串包含检测 返回布尔序列,判断是否包含子串
print(df)
# 6. 数据分箱与离散化 数值分箱(等宽/等频) pd.cut(), pd.qcut(), 离散化应用场景
df = pd.DataFrame({'id':[101,102,103,104,105,106,107,108]
,'age':[18,19,20,19,35,60,88,100]})
print(df)
# 等宽分箱,将数值列分为等宽区间(如分为低/中/高)
# bins 切分区间的数值列表或者整数。如果是整数,则表示将数据均匀地分成多少个区间。如果是列表,则需要指定每个区间的边界。
# right 默认True,表示每个区间的右端点是闭区间,即包含右端点。如果设置为False,则左端点为闭区间。
# labels 传入一个列表指定每个区间的标签。
df['fx_value'] = pd.cut(df['age'], bins=3) #等分为三份,即每份为(100-18)/3,则第一个区间为(18, 18+(100-18)/3]
df['fx_label'] = pd.cut(df['age'], bins=3,labels=['低','中','高'])
df['fx1_value'] = pd.cut(df['age'], bins=[1,18,30,60,100])
df['fx1_label'] = pd.cut(df['age'], bins=[1,18,30,60,100],labels=['少年','青年','中年','老年'])
# 等频分箱,将数值列分为等频区间(每箱数据量相同)
df['fx2_value'] = pd.qcut(df['age'], q=4)
print(df)
# 7. 其他常用转换 重命名列、索引操作、函数应用、内存优化 rename(), set_index(), apply(), 类型优化减少内存占用
# inplace 当设为 True 时,会直接在原 DataFrame上进行修改;若设为 False(默认值),则会返回一个新的 DataFrame,原DataFrame 保持不变
df = pd.DataFrame({'id':[101,102,103,104],'name':['zhang3','li4','wang5','zhao6']})
df.set_index("id",inplace=True)
print(df)
df.reset_index(inplace=True)
print(df)
df.rename(index={0:1,1:2},columns={"name": "姓名"},inplace=True) # 重命名列和部分行索引
print(df)
#重新赋值 批量修改
df.index = ["Ⅰ", "Ⅱ", "Ⅲ", "Ⅳ"]
df.columns = ["id", "名称"]
#添加列
df["age"] = ["11", "12", "13", "14"]
df["salary"] = ["1", "2", "3", "4"]
print(df)
#删除列
# 通过 df.drop(“列名”, axis=1) 删除,
df.drop("age", axis=1, inplace=True) # 也可是删除行 axis=0
del df["salary"]
print(df)
#插入列 通过 insert(loc, column, value) 插入。该方法没有inplace参数,直接在原数据上修改。
df.insert(loc=0, column="age", value=df["id"] * 2)
print(df)
5)时间数据处理
- Timestamp 是 pandas 对 datetime64 数据类型的一个封装
- datetime64 是 NumPy 中的一种数据类型,用于表示日期和时间,而 pandas 基于 datetime64 构建了 Timestamp 类
- 当 pd.to_datetime 接收单个日期时间值时,会返回 Timestamp 对象
import pandas as pd
# 时间戳timestamp
d = pd.Timestamp("2001-01-01 12:12:12.123456")
# 属性
print('年:', d.year)
print('月:', d.month)
print('日:', d.day)
print('小时:', d.hour)
print('分钟:', d.minute)
print('秒:', d.second)
print('微秒:', d.microsecond)
print('季度:', d.quarter) # 1
print('是否是月底:', d.is_month_end) # False
print('是否是月初:', d.is_month_start) # True
print('是否是年底:', d.is_year_end) # False
print('是否是年初:', d.is_year_start) # True
# 方法
print('星期几:', d.day_name()) # Monday
print('转换为天:', d.to_period("D")) # 2001-01-01
print('转换为年度:', d.to_period("Y")) # 2001 freq:用于指定要转换的时间周期频率
print('转换为季度:', d.to_period("Q")) # 2001Q1
print('转换为月度:', d.to_period("M")) # 2001-01
print('转换为周维度:', d.to_period("W")) # 2001-01-01/2001-01-07
# 字符串转换为日期类型
print(pd.to_datetime('2025-07-01'), type(pd.to_datetime('2025-07-01'))) #
print(pd.to_datetime('20250409'))
print(pd.to_datetime('2025/04/13'))
print(pd.to_datetime('2025-07'))
df = pd.DataFrame({
'id': [1, 2, 3],
'date': ['2025-01-01 10:00', '2025-02-02 11:00', '2025-03-03 14:00']
})
df['datetime'] = pd.to_datetime(df['date'])
print(type(df['datetime'].dt)) # .dt的类型是 DatetimeProperties
print(df['datetime'].dt.day_name()) #
print(df)
# 将日期数据作为索引 可以直接使用时间进行切片取值
df.set_index("datetime", inplace=True) # 将date列设置为索引,inplace=true直接修改原对象
print(df)
# 将时间作为索引后
print(df.loc['2025-01'])
print(df.loc['2025-01':'2025-02'])
# 通过between_time()和at_time()获取某些时刻的数据
print(df.between_time('10:00', '12:00'))
print(df.at_time('11:00'))
# 将时间间隔timedelta 作为索引 可以直接使用时间进行切片取值。
# 当用一个日期减去另一个日期,返回的结果是timedelta64类型。
d1 = pd.Timestamp("2015-05-01 09:08:07.123456")
d2 = pd.Timestamp("2015-05-31 09:23:07.123456")
print(d2 - d1) # 30 days 00:15:00
print(type(d1)) # <class 'pandas._libs.tslibs.timestamps.Timestamp'>
print(type(d2 - d1)) # <class 'pandas._libs.tslibs.timestamps.Timestamp'>
# TimedeltaIndex
# 将timedelta64类型的数据设置为索引,得到的就是TimedeltaIndex。
# 将时间作为索引后可以直接使用时间进行切片取值。
df = pd.DataFrame({
'id': [1, 2, 3],
'date': ['2025-01-01 10:00', '2025-02-02 11:00', '2025-03-03 14:00']
})
df['datetime'] = pd.to_datetime(df['date']) - pd.Timestamp("2025-01-01")
df.set_index('datetime', inplace=True)
print(df.loc["30 days":"40 days"])
print(df)
# 5. 生成时间序列
# date_range() 创建一个有规律的日期序列,
print(pd.date_range("2025-01-01", "2025-02-10")) # 通过开始日期、结束日期
print(pd.date_range("2025-01-01", periods=12, freq='ME')) # 通过开始日期、频率(默认的频率是天)
print(pd.date_range("2025-01-01", periods=5, freq='1h30min')) # 组合频率
# 6.重新采样
# 处理时间序列数据时,经常需要按照新的频率对数据进行重新采样。
# resample()方法以数据累计为基础,会将数据按指定的时间周期进行分组,之后可以对其使用聚合函数。
df = pd.DataFrame({
'id': [1, 2, 3],
'age': [11, 12, 13],
'date': pd.date_range("2025-01-01", periods=3)
})
df.set_index('date', inplace=True)
print(df)
print(df.resample('YE').mean())
6)统计分析
import pandas as pd
df = pd.DataFrame({
'id':[1,2,3,4,5],
'name':['zhang3','li4','wang5','zhao6','qian7'],
'age':[11,12,13,14,15],
'sex':['man','man','man','woman','unknown'],
'salary':[100,200,300,400,500],
'salary2':[10,20,30,40,50]
})
print(df.describe()) # 描述性统计
print(df.groupby('sex').groups) # 查看分组结果 {'man': [0, 1, 2], 'unknown': [4], 'woman': [3]}
print(df.groupby('sex').get_group('man')) # 查看分组man包含的数据,返回DataFrame数据
# 分组后默认会将分组字段作为行索引。如果分组字段有多个,得到的是复合索引
print(df.groupby('sex')[['salary','age']].sum()) # 多字段聚合
print(df.groupby(['sex','age'])['salary'].sum()) # 多字段分组
# 可以通过agg()或aggregate()进行更复杂的操作,如一次计算多个统计值
print(df.groupby('sex')['salary'].agg(['min','max']))
# 也可以在agg()中传入字典,对多个列计算不同的统计值。可以在agg()后通过rename()对统计后的列重命名。
print(df.groupby('sex').agg({'salary':['max','min'],'age':'sum' })
.rename(columns={'salary':'工资','age':'年龄','max':'最高工资'}))
# 可以向agg()中传入自定义函数进行计算
print(df.groupby('sex')['name'].agg(lambda x: [name[0] for name in x])) # 将每个分组内的姓名的首字母组成的list
# 分组转换 不改变行数,根据分组数据添加计算列(如占比、排名)
df['sex_sal_rate'] = df.groupby('sex')['salary'].transform(lambda x: x/x.sum())
print(df)
# 分组过滤 根据组级条件筛选数据(如剔除样本量不足的组)
print(df.groupby('sex').filter(lambda x: len(x) > 1))
print(df.groupby('sex')[['age','salary']].corr()) # 相关性分析 可结合分组聚合结果 分析不同分组下变量的关联性(如各地区的价格-销量相关性)
print(df)
4、数据可视化
1)matplotlib
-
Matplotlib是一个Python绘图库,广泛用于创建各种类型的静态、动态和交互式图表。它是数据科学、机器学习、工程和科学计算领域中常用的绘图工具之一
-
支持多种图表类型:折线图(Line plots)、散点图(Scatter plots)、柱状图(Bar charts)、直方图(Histograms)、饼图(Pie charts)、热图(Heatmaps)、箱型图(Box plots)、极坐标图(Polar plots)、3D图(3D plots,配合 mpl_toolkits.mplot3d)
-
高度自定义:允许用户自定义图表的每个部分,包括标题、轴标签、刻度、图例等。支持多种颜色、字体和线条样式。提供精确的图形渲染控制,如坐标轴范围、图形大小、字体大小等
-
兼容性:与NumPy、Pandas等库紧密集成,特别适用于绘制基于数据框和数组的数据可视化。可以输出到多种格式(如PNG、PDF、SVG、EPS等)
-
动态图表:可以生成动画(使用FuncAnimation类),为用户提供动态数据的可视化
-
Matplotlib有两种画图接口:一个是便捷的MATLAB风格的有状态的接口,另一个是功能更强大的面向对象接口
import numpy as np
import random
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams["font.sans-serif"] = ["SimHei"] #指定中文字体
# rcParams["font.sans-serif"] = ['STHeiti'] #mac
# 1、创建图表,并设置大小
plt.figure(figsize=(10,6))
# ------------------------------ 折线图/柱状图/条形图
'''
# 2、准备数据和绘图
month = ['1月','2月','3月','4月']
sales = [100,150,80,130]
# 2.1 折线图
# plt.plot(month, sales,
# label='产品A',
# color='orange',
# linewidth=2,
# linestyle='--',
# marker='o',)
# 2.2 柱状图
# plt.bar(month, sales,label='产品B', color='skyblue', width=0.6) # label是图例的名称
# 2.3 条形图
# plt.barh(month, sales, label='产品A', color='orange',)
# 3、自定义参数
# 添加标题
plt.title("这是标题",fontsize=16,color='red')
# 添加坐标轴的标签
plt.xlabel('这是X轴',fontsize=12)
plt.ylabel('这是Y轴',fontsize=12)
# 添加图例
plt.legend(loc='upper left')
# 添加网格线
plt.grid(True,alpha=0.1,color='blue',linestyle='--')
# plt.grid(axis='y', linestyle='--', alpha=0.6) # 只在y轴上绘制,即水平线
# 自定义刻度字体大小
plt.xticks(rotation=0,fontsize=10)
plt.yticks(rotation=0,fontsize=10)
# 自定义y轴范围
# plt.ylim(0,200) # 折现和柱状图使用
# 在每个数据上方添加数值标签
# 方式1
# for xi, yi in zip(month, sales):
# print(xi,yi) # 1月 100
# plt.text(xi, yi + 2, str(yi), ha='center',fontsize=10) # ha: 水平对齐方式
# 方式2
for i, v in enumerate(sales):
print(i,v) # 0 100
plt.text(i, v + 2, str(v), ha='center', fontsize=10)
'''
# ------------------------------ 饼图/环形图/爆炸式饼图
'''
# 2、准备数据和绘图
month = ['1月','2月','3月','4月']
sales = [100,150,80,130]
colors = ['#66b3ff','#99ff99','#ffcc99','#ff9999']
# 2.1 创建饼图
# plt.pie(sales,
# labels=month,
# colors=colors,
# autopct='%.1f%%', # 显示百分比
# startangle=90) # 起始角度
# 2.2 环形图
# plt.pie(sales, labels=month, colors=colors,
# autopct='%.1f%%',startangle=90,
# wedgeprops={'width': 0.5}, # 控制环的宽度(0.3~0.7)
# pctdistance=0.85) # pctdistance调整百分比位置
# 2.3 爆炸式饼图
explode = (0.1, 0, 0.3, 0) # 突出第1、3块
plt.pie(sales,
labels=month, colors=colors,
autopct='%.1f%%',startangle=90,
explode=explode, shadow=True )
# 3、自定义参数
plt.title("这是标题",fontsize=16,color='red')
# 添加图例
plt.legend(loc='upper left')
# 在中心添加文字 (适合环形图)
plt.text(0, 0, "总计\n100%", ha='center', va='center', fontsize=12)
'''
# ------------------------------ 散点图/箱线图
''' '''
# 2、准备数据和绘图
# 2.1 散点图1
# x = np.array([1,2,3,4,5,6,7,8,9,10])
# y = np.power(x,2)
# plt.scatter(x, y, color='green', s=60)
# 2.2 散点图2
# random.seed(42)
# x = [random.uniform(0, 10) for _ in range(1000)] # X值:0~10均匀分布
# y = [xi * 2 + random.gauss(0, 2) for xi in x] # Y值:2倍X值 + 高斯噪声
# plt.scatter(
# x, # X轴坐标数据
# y, # Y轴坐标数据
# color='blue', # 点的填充颜色为蓝色
# alpha=0.5, # 透明度为50%(半透明)
# s=20, # 点的大小为20平方磅
# edgecolors='none', # 点边缘无颜色(无边框)
# label='数据点' # 图例中显示的标签文本
# )
# #绘制回归线
# plt.plot([0, 10],
# [0,20],
# color='red', linestyle='--', linewidth=2,
# label=f'回归线')
# 2.3 箱线图
''' 展示数据的分布、极值、中位数、异常值
• 中位数:盒子中间的线
• 上/下四分位数:盒子上下边缘
• 离群值:落在“胡须”外的点
'''
data = {
'语文': [70, 76, 82, 83, 84, 85, 88, 90, 95], # 箱体较长 → 成绩分布较分散 有一个异常值
'数学': [75, 79, 80, 82, 87, 88, 89, 92, 93], # 中位数最高,且箱体较短 → 学生成绩集中且整体较好。
'英语': [65, 68, 70, 72, 78, 80, 85, 90, 95] # 中位数最低(约78分),但箱须向上延伸较长 → 部分学生成绩较高
}
plt.boxplot(data.values(), tick_labels=data.keys())
# 3、自定义参数
# 添加标题
plt.title("这是标题",fontsize=16,color='red')
# 添加坐标轴的标签
plt.xlabel('这是X轴',fontsize=12)
plt.ylabel('这是Y轴',fontsize=12)
# 添加图例
plt.legend(loc='upper left')
# 添加网格线
plt.grid(True,alpha=0.1,color='blue',linestyle='--')
# plt.grid(axis='y', linestyle='--', alpha=0.6) # 只在y轴上绘制,即水平线
# 自定义刻度字体大小
plt.xticks(rotation=0,fontsize=10)
plt.yticks(rotation=0,fontsize=10)
# 自定义y轴范围
# plt.ylim(0,200) # 折现和柱状图使用
# 在每个数据上方添加数值标签
# for i in range(len(a)):
# plt.text(a[i]+0.2, b[i], f"{b[i]}", fontsize=9)
# 4、自动优化排版
plt.tight_layout()
# 5、显示图表
plt.show()
2)seaborn
-
Seaborn是一个基于Matplotlib的Python可视化库,旨在简化数据可视化的过程
-
它提供了更高级的接口,用于生成漂亮和复杂的统计图表,同时也能保持与Pandas数据结构的良好兼容性
-
在Seaborn中,样式(style)控制了图表的整体外观,包括背景色、网格线、刻度线等元素
-
Seaborn提供了一些内置的样式选项
- white:纯白背景,没有网格线
- dark:深色背景,带有网格线
- whitegrid:白色背景,带有网格线
- darkgrid:深色背景,带有网格线(默认样式)
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["KaiTi"] plt.figure(figsize=(12, 6)) sns.set_style("darkgrid") # 1、直方图 # sns.histplot(data=df, x="xxx") # 在直方图中设置kde=True也可以得到核密度估计图 # sns.histplot(data=df, x="xxx", kde=True) ''' 2、核密度估计图(KDE,Kernel Density Estimate Plot)是一种用于显示数据分布的统计图表 它通过平滑直方图的方法来估计数据的概率密度函数,使得分布图看起来更加连续和平滑。 核密度估计是一种非参数方法,用于估计随机变量的概率密度函数。 其基本思想是,将每个数据点视为一个“核”(通常是高斯分布),然后将这些核的贡献相加以形成平滑的密度曲线。 ''' # sns.kdeplot(data=df, x="xxx") ''' 3、计数图 用于绘制分类变量的计数分布图,显示每个类别在数据集中出现的次数,是分析分类数据非常直观的工具,可以快速了解类别的分布情况 ''' # sns.countplot(data=df, x="xxx") # 3、散点图 #可通过hue参数设置不同组别进行对比 # sns.scatterplot(data=df, x="xxx", y="yyy", hue="sex") # 可以通过regplot()函数绘制散点图,同时会拟合回归曲线。可以通过fit_reg=False关闭拟合。 # sns.regplot(data=df, x="xxx", y="flipper_length_mm") # 也可以通过lmplot()函数绘制基于hue参数的分组回归图 # sns.lmplot(data=df, x="xxx", y="yyy", hue="sex") # 也可以通过jointplot()函数绘制在每个轴上包含单个变量的散点图 # sns.jointplot(data=df, x="xxx", y="yyy") # 4、蜂窝图 # 通过jointplot()函数,设置kind="hex"来绘制蜂窝图。 # sns.jointplot(data=df, x="xxx", y="yyy", kind="hex") # 5、二维核密度估计图 # 通过kdeplot()函数,同时设置x参数和y参数来绘制二维核密度估计图。 # sns.kdeplot(data=df, x="body_mass_g", y="flipper_length_mm") # 通过fill=True设置为填充,通过cbar=True设置显示颜色示意条。 # sns.kdeplot(data=df, x="xxx", y="yyy", fill=True, cbar=True) # 6、条形图 # 条形图会按x分组对y进行聚合,通过estimator参数设置聚合函数,并通过errorbar设置误差条,误差条默认会显示。可以通过误差条显示抽样数据统计结果的可能统计范围,如果数据不是抽样数据, 可以设置为None来关闭误差条。 # sns.barplot(data=df, x="xxx", y="yyy", estimator="mean", errorbar=None) ''' 7、箱线图 箱线图是一种用于展示数据分布、集中趋势、散布情况以及异常值的统计图表。它通过五个关键的统计量(最小值、第一四分位数、中位数、第三四分位数、最大值)来展示数据的分布情况。 箱线图通过箱体和须来表现数据的分布,能够有效地显示数据的偏斜、分散性以及异常值。箱线图的组成部分: 箱体(Box): ○ 下四分位数(Q1):数据集下 25% 的位置,箱体的下边缘。 ○ 上四分位数(Q3):数据集下 75% 的位置,箱体的上边缘。 ○ 四分位间距(IQR, Interquartile Range):Q3 和 Q1 之间的距离,用来衡量数据的离散程度。 ○ 中位数(Median):箱体内部的水平线,表示数据集的中位数。 须(Whiskers): ○ 下须:从 Q1 向下延伸,通常是数据集中最小值与 Q1 的距离,直到没有超过1.5倍 IQR 的数据点为止。 ○ 上须:从 Q3 向上延伸,通常是数据集中最大值与 Q3 的距离,直到没有超过1.5倍 IQR 的数据点为止。 异常值(Outliers): ○ 超过1.5倍 IQR 的数据被认为是异常值,通常用点标记出来。异常值是数据中相对于其他数据点而言“非常大”或“非常小”的值。 ''' # sns.boxplot(data=df, x="xxx", y="yyy") ''' 8、小提琴图(Violin Plot) 是一种结合了箱线图和核密度估计图(KDE)的可视化图表, 用于展示数据的分布情况、集中趋势、散布情况以及异常值。 小提琴图不仅可以显示数据的基本统计量(如中位数和四分位数),还可以展示数据的概率密度,提供比箱线图更丰富的信息。 ''' # sns.violinplot(data=df, x="xxx", y="yyy") ''' 9、成对关系图 成对关系图是一种用于显示多个变量之间关系的可视化工具。它可以展示各个变量之间的成对关系,并且通过不同的图表形式帮助我们理解数据中各个变量之间的相互作用。 对角线上的图通常显示每个变量的分布(如直方图或核密度估计图),帮助观察每个变量的单变量特性。其他位置展示所有变量的两两关系,用散点图表示。 ''' # sns.pairplot(data=df, hue="xxx") plt.title('这是标题', fontsize=14) plt.xticks(rotation=45) plt.tight_layout() plt.show()
3)pandas
- pandas提供了非常方便的绘图功能,可以直接在DataFrame或Series上调用plot()方法来生成各种类型的图表
- 底层实现依赖于Matplotlib,pandas的绘图功能集成了许多常见的图形类型,易于使用。
import pandas as pd
df = xxx
# 使用柱状图展示不同睡眠时长的数量。
pd.cut(df["xxx"], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().plot.bar(
color=["red", "green", "blue", "yellow", "cyan", "magenta", "black", "purple"]
)
# 折线图
# 折线图通常用于展示连续数据的变化趋势。它通过一系列数据点连接成的线段来表示数据的变化。能够清晰地展示数据的趋势和波动。
# 使用折线图展示不同睡眠时长的数量。
# pd.cut(df["xxx"], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().sort_index().plot()
# 面积图
# 面积图是折线图的一种变体,线下的区域被填充颜色,用于强调数据的总量或变化。可以更直观地展示数据量的变化,适合用来展示多个分类的累计趋势。
# 使用面积图展示不同睡眠时长的数量。
# pd.cut(df["xxx"], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().sort_index().plot.area()
# 直方图
# 直方图用于展示数据的分布情况。它将数据范围分成多个区间,并通过矩形的高度显示每个区间内数据的频率或数量。可以揭示数据分布的模式,如偏态、峰度等。
# 使用直方图展示不同睡眠时长的数量。
# df["xxx"].value_counts().plot.hist()
# 饼状图
# 饼状图用于展示一个整体中各个部分所占的比例。它通过一个圆形图形分割成不同的扇形,每个扇形的角度与各部分的比例成正比。能够快速展示各部分之间的比例关系,但不适合用于展示过多的类别或比较数值差异较小的部分。
# 使用饼状图展示不同睡眠时长的占比。
# pd.cut(df["xxx"], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().sort_index().plot.pie()
# 散点图
# 散点图通过在二维坐标系中绘制数据点来展示两组数值数据之间的关系。能够揭示两个变量之间的相关性和趋势。
# 绘制睡眠时间与睡眠质量的散点图。
# df.plot.scatter(x="xxx", y="yyy")
# 蜂窝图
# 蜂窝图是散点图的扩展,通常用于表示大量数据点之间的关系。它通过将数据点分布在一个六边形网格中,每个六边形的颜色代表其中的数据密度。适合展示大量数据点,避免了散点图中的过度重叠问题。
# 绘制睡眠时间与睡眠质量的蜂窝图。
# df.plot.hexbin(x="xxx", y="yyy", gridsize=10)
# 使用柱状图展示不同睡眠时长的数量。
pd.cut(df["xxx"], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().plot.bar(
color=["red", "green", "blue", "yellow", "cyan", "magenta", "black", "purple"]
)
# 折线图
# 折线图通常用于展示连续数据的变化趋势。它通过一系列数据点连接成的线段来表示数据的变化。能够清晰地展示数据的趋势和波动。
# 使用折线图展示不同睡眠时长的数量。
# pd.cut(df["xxx"], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().sort_index().plot()
# 面积图
# 面积图是折线图的一种变体,线下的区域被填充颜色,用于强调数据的总量或变化。可以更直观地展示数据量的变化,适合用来展示多个分类的累计趋势。
# 使用面积图展示不同睡眠时长的数量。
# pd.cut(df["xxx"], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().sort_index().plot.area()
# 直方图
# 直方图用于展示数据的分布情况。它将数据范围分成多个区间,并通过矩形的高度显示每个区间内数据的频率或数量。可以揭示数据分布的模式,如偏态、峰度等。
# 使用直方图展示不同睡眠时长的数量。
# df["xxx"].value_counts().plot.hist()
# 饼状图
# 饼状图用于展示一个整体中各个部分所占的比例。它通过一个圆形图形分割成不同的扇形,每个扇形的角度与各部分的比例成正比。能够快速展示各部分之间的比例关系,但不适合用于展示过多的类别或比较数值差异较小的部分。
# 使用饼状图展示不同睡眠时长的占比。
# pd.cut(df["xxx"], [0, 5, 6, 7, 8, 9, 10, 11, 12]).value_counts().sort_index().plot.pie()
# 散点图
# 散点图通过在二维坐标系中绘制数据点来展示两组数值数据之间的关系。能够揭示两个变量之间的相关性和趋势。
# 绘制睡眠时间与睡眠质量的散点图。
# df.plot.scatter(x="xxx", y="yyy")
# 蜂窝图
# 蜂窝图是散点图的扩展,通常用于表示大量数据点之间的关系。它通过将数据点分布在一个六边形网格中,每个六边形的颜色代表其中的数据密度。适合展示大量数据点,避免了散点图中的过度重叠问题。
# 绘制睡眠时间与睡眠质量的蜂窝图。
# df.plot.hexbin(x="xxx", y="yyy", gridsize=10)

743

被折叠的 条评论
为什么被折叠?



