目录

1. 为什么要学习数据分析

2. Numpy

3. Pandas

4. Pandas数据分析

5. 数据可视化

6. 实战练习

为什么要学习数据分析

Excel与Python对比

功能 Excel Python
数据处理量 1万行以内 100万行以上
自动化 手动操作 代码自动化操作

数据分析使用python可自动化大量地处理数据


数据分析流程

Numpy高性能数值计算               Pandas表格数据处理                Matplotlib数据可视化


Anaconda

Anaconda下载: Anaconda

Anaconda是简化Python/R编程语言管理包和配置环境,开源的数据科学和机器学习的集成环境


Jupyter Notebook 与 Jupyter Lab区别

工具 适用场景
Jupyter Notebook

单文档,简单的交互任务

Jupyter Lab

多文档协做,复杂的开发工作流程,同时编写代码,运行终端


为什么使用Jupyter Notebook而不是使用python文件编写代码

Jupyter Notebook每个Cell的变量是全局变量       Markdown模型下 # 代表标题

Jupyter Notebook  可以跟代码进行交互,比python文件编写代码与数据交互更方便


Jupyter快捷键

命令 功能
esc 从输入模式推出到命令模式
a 在Cell上面再创建新的Cell
b 在Cell下面再创建新的Cell
dd 删除当前Cell
m 切换到Markdown文本编辑模式
y 切换到code代码模式
ctrl + 回车 运行Cell
shift + 回车 运行当前Cell并创建一个新Cell

Numpy

概述  Numpy是Python科学计算与数值运行的基础包


ndarray多维

# 导包
import numpy as py
# 创建0为数组
arr = np.array(5)
# 创建1为数组
arr = np.array([1, 2, 3])
# 创建2为数组
arr = np.array([[1, 2],[3, 4]])

当数组内数据是不同数据类型则转化为同类型 , 优先级(字符型>浮点型>整数型)


ndarray属性

# 创建3维数组
arr = np.array([ [[1, 2, 3],[4, 5, 6]], [[6, 5, 4],[3, 2, 1]] ])
# 输出数组形状
print(arr.shape)
# 输出数组维数
print(arr.ndim)
# 输出数组元素总个数
print(arr.size)
# 输出数组元素类型
print(arr.dtype)
# 输出数组的转置数组
print(arr.T)
# 输出数组单个元素内存
print(arr.itemsize)
# 输出数组总内存
print(arr.nbytes)
# 输出数组内存的存储方式
print(arr.flags)


# 执行以上代码,输出数组相关信息
(2, 2, 3) 3 12 int32 [ [[1, 6],[4, 3]],  [[2, 5],[5,2]], [[3,4],[6 1]] ] 4 48
C_CONTIGUOUS : True     F_CONTIGUOUS : False     OWNDATA : True
WRITEABLE : True           ALIGNED : True            WRITEBACKIFCOPY : False

ALIGNED按硬件要求对齐    WRITEBACKIFCOPY延迟写回副本

OWNDATA表示拥有自己的数据内存    WRITEABLE表示允许修改元素值

C_CONTIGUOUS是C 风格连续存储行优先  F_CONTIGUOUS是Fortran 风格连续存储列优先


ndarray创建

基础创建
# 基础创建
list1 = [1, 2, 3]
# 创建一个数组
arr = np.array( list1 )
arr = np.array([1, 2, 3])
# 创建数组并定义数据类型
arr = np.array(list1, dtype=np.float64)
数组复制
# 创建数组并复制赋值
arr1 = np.copy(arr)
预定义形状

全0数组  全1数组  空值数组  填充数组

# 全0一维数组
arr = np.zeros(8, dtype=int)
# 全0二维数组
arr = np.zeros((2, 3),dtype=int)
# 全0复制格式数组
arr = np.zeros_like(arr)

# 全1一维数组
arr = np.ones(8, dtype=int)
# 全1二维数组
arr = np.ones((2, 3),dtype=int)
# 全1复制格式数组
arr = np.ones_like(arr)

# 空值一维数组
arr = np.empty(8, dtype=int)
# 空值二维数组
arr = np.empty((2, 3),dtype=int)
# 空值复制格式数组
arr = np.empty_like(arr)

# 填充一维数组
arr = np.full(8, 2025, dtype=int)
# 填充二维数组
arr = np.full((2, 3), 2025, dtype=int)
# 填充复制格式数组
arr = np.full_like(arr, 2026)

empty函数不是生成随机数,,而是生成分配内存后保留在该内存原有的"垃圾值"

等差/线性/对数等分数列
# 等差间隔数列
# 参数类型 start,end+1,step  包左不包右
arr = np.arange(1, 10, 1)
# 输出
[1 2 3 4 5 6 7 8 9]


# 等间间隔数列
# 参数类型 start,end,step  包左包右
arr = np.linspace(0, 100, 5)
arr = np.arange(0, 101, 25)
# 输出
[  0.  25.  50.  75. 100.]
[  0  25  50  75 100]

# 对数间隔数列
# 参数类型 start,end,step  包左包右
arr = np.logspace(0,4,3,base=2)
# 输出
[ 1.  4. 16.]

矩阵的创建

单位/对角矩阵
# 单位矩阵,3行3列
arr = np.eye(3, dtype=int)
arr = np.eye(3,3 dtype=int)
# 输出
[[1 0 0]
 [0 1 0]
 [0 0 1]]
# 单位矩阵,3行4列
arr = np.eye(3, 4, dtype=int)
# 输出
[[1 0 0]
 [0 1 0]
 [0 0 1]]

# 对角矩阵
arr = np.diag([1, 2, 3])
# 输出
[[1 0 0]
 [0 2 0]
 [0 0 3]]
随机数值

均匀/正态分布/随机种子

# 随机[0,1)浮点数均匀分布,2行3列
arr = np.random.rand(2, 3)
# 随机指定[3,6)浮点数均匀分布,2行3列
arr = np.random.uniform(3, 6, (2, 3))
# 随机指定[3,6)整数均匀分布,2行3列
arr = np.random.randint(3, 6, (2, 3))

# 正态分布 (-3 3之间),2行3列
arr = np.random.randn(2, 3)

# 随机种子
np.random.seed(20)
arr = np.random.randint(1, 10, (2, 5))
数据类型

布尔/整数/浮点/复数型

# 布尔型
arr = np.array([1, 0, 1],dtype='bool')
# 输出
[ True False  True]

# 整数型
arr = np.array([1, 2, 3], dtype=np.int8)
# 输出
[1 2 3]

# 浮点型
arr = np.array([1, 2, 3], dtype=np.float64)
# 输出
[1. 2. 3.]

# 复数型
arr = np.array([1, 2, 3], dtype=np.complex128)
[1.+0.j 2.+0.j 3.+0.j]

索引切片与运算

索引切片与slice函数运用
# 索引与切片,索引从0开始
# 创建一维随机数组
arr = np.random.randint(1, 100, 20)
# 取第11个元素
print(arr[:]) # 所有元素
print(arr[10]) # 第11个元素
print(arr[1:5])  # 1到4个元素 start:end+1 包左不包右

# 索引与切片,使用布尔索引
# 10以上的元素 
print(arr[arr>10])
# 10到50的元素
print(arr[(arr>10) & (arr<50) ])
# 小于10或大于50的元素
print(arr[(arr<10) | (arr>50) ])

# slice切片函数
# start:end+1:step 起始,终点,步长 包左不包右
# 2到4的元素
print(arr[slice(2,5)])
# 2到9的元素,步长为2
print(arr[slice(2, 10, 2)]) 
print(arr[::-1]) # 反转

# 二维数组切片
arr = np.random.randint(1, 100, (4, 8))
# 切片二行3列数
print(arr[1, 2])
# 切片第二行2到4元素
print(arr[1,2:5])

# 大于50的数
print(arr[arr>50])
# 二行3到4列且大于50
print(arr[2,2:5][arr[2,2:5]>50])
# 二列3到4列且大于50
print(arr[2:3,2][arr[2:3,2]>50])
矩阵运算

矩阵按位加减乘除,矩阵乘

# 同类型矩阵运算
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)
# 简单同位相减
print(a - b)
# 简单同位相乘
print(a * b)
# 简单同位相除
print(a / b)
# # 简单同位平方
print(a ** 2)


类型不同,若不可广播机制则报错
a = np.array([1, 2, 3])  # 1*3型
b = np.array([4], [5], [6])  # 3*1型
# 可广播相加
print(a+b)
[[5 6 7]
 [6 7 8]
 [7 8 9]]
# 可广播相乘
print(a*b)
[[ 4  8 12]
 [ 5 10 15]
 [ 6 12 18]]

# 矩阵乘@
print(a@b)

Numpy常用函数

基本函数

平方sqrt 自然数指数exp 自然数对数log 三角sin cos 绝对值abs 指数power 取舍round

# 计算平方根,返回浮点数
list1 = np.array([1, 4, 9])
arr = np.sqrt(list1)
print(np.sqrt([1, 4, 9]))

# 计算自然数的指数
print(np.exp(1))
# 输出
2.718

# 计算自然对数
print(np.log(2.718))
# 输出
0.999896315728952 

# 计算三角函数
print(np.sin(np.pi/2))
# 输出1.0
print(np.sin(1))
# 输出0.8414709848078965

print(np.cos(1))
# 输出0.5403023058681398
print(np.cos(np.pi))
# 输出-1.0

# 计算绝对值
print(np.abs(arr))

# 计算指数
print(np.power(arr,3))

# 四舍六入五凑偶
print(np.round([3.2, 4.5, 8.1]))  

# 向上取整,向下取整
arr = np.array([1.6, 25.1, 81.7])
print(np.ceil(arr))
print(np.floor(arr))

# 检查缺失值
np.isnan([1, 2, np.nan, 3])
统计函数

求和sum  计算平均值mean  计算中位数media  方差var  标准差std  最大值max  最小值min

最大值索引argmax  最小值索引argmin  计算分位数percentile 累积和cumsum 累积差cumprod

# 随机一维数组
arr = np.random.ranint(1, 20, 8)

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

# 平均值
print(np.mean(arr))

# 中位数 排序后奇数取中间,偶数取中间两个平均值 比较平均数和中位数
print(np.median(arr))

# 方差/标准差
print(np.var(arr))
print(np.std(arr))

# 最大值和最小值
print(np.max(arr), np.argmax(arr))
print(np.min(arr), np.argmin(arr))

# 分位数
print(np.percentile(arr,50))
44 47 64 67
# 百分之25
0.25*3=0.75
(47-44)*0.75+44=46.25
# 百分之80
3*0.8=2.4
(67-64)*0.4+64=65.2

# 累积和 累积积
arr = np.array([1, 2, 3])
print(np.cumsum(arr))
[1 3 6]
print(np.cumprod(arr))
[1 2 6]
比较函数

大于greater 小于less 等于equal 与logical_and  或logical_or 非logical_not 至一真any 全真all

# 输出大于4的值
print(np.greater([3, 4, 5, 6, 7], 4))
# 输出小于4的值
print(np.less([3, 4, 5, 6, 7], 4))
# 输出等于4的值
print(np.equal([3, 4, 5, 6, 7], 4))
# 布尔值判断是否对等
print(np.equal([3, 4, 5, 6, 7], [4, 5, 6, 6, 8]))

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

# 检查元素是否至少有一个为True
print(np.any([0, 0, 0, 1]))
# 检查元素是否全为为True
print(np.all([0, 0, 0, 1]))
自定义条件

自定义函数where 选择函数select

# 基础语法
print(np.where(条件,符合条件,不符合条件))

# 创建一维组
arr = np.array([1, 2, 3, 4, 5])
# arr大于3,输出arr,否则输出0
print(np.where(arr>3,arr,0))
[0 0 0 4 5]

# 创建一维组
arr = np.array([1,2,3,4,5])
# arr大于3,输出1,否则输出0
print(np.where(arr<3,1,0))

# 自定义函数
arr = np.random.randint(0, 101, 10)
print(np.where(score>=60,'及格','不及格'))
# 创建自定义函数,[0,60)不及格,[60,80)良好,[81,100]优秀
print(np.where(
        score<60,'不及格',np.where(
                score<80,'良好','优秀' 
        )
))

# select函数比where自定义函数简单
np.select(条件,返回结果)
print(np.select([score>80,(score>60)&(score<80),score<60,],['优秀', '良好', '不及格'],default=''未知))
排序/去重/拼接/分割/调整函数

排序sort 去重unique 拼接concatenate 分割split 调整shape

# 创建一维数组
arr = np.random.randint(1,100,20)
# 直接打印并改变数值序列
arr.sort()  
# print打印保留数值序列
print(np.sort(arr))

# 去重
print(np.unique(arr))

# 数组拼接
print(arr1+arr2)
print(np.concatenate((arr1,arr2)))

# 数组分割
# 能等分
print(np.split(arr,5))
# 不等分
print(np.split(arr,[6, 12, 18]))

# 调整形状
print(np.reshape(arr,[5,4]))

NumPy科学计算综合练习

第一题 一周气温[ 28, 30, 29, 31, 32, 30, 29 ]分析

# 创建数组
temp = np.array([ 28, 30, 29, 31, 32, 30, 29 ])
# 最高气温
print(np.max(temp))
# 最低气温
print(np.min(temp))
# 平均气温,保留3位小数
print('%.3f'%np.mean(temp))
# 超30度气温
print(len(temp[temp>30]))

# 自定义条件判断
print(np.where(temp>30,1,0))
# 累加和
print(np.cumsum(np.where(temp>30,1,0))[-1])
# 非0计算
print(np.count_nonzeros(temps>30))

第二题 学生成绩[ 85, 90, 78, 92, 88 ]分析

# 创建数组
score = np.array([ 85, 90, 78, 92, 88 ])
# 平均数
print(np.mean(score))
# 中位数
print(np.median(score))
# 标准差
print('%.3f'%np.std(score))
# 转为满分10分
print(score/10)

第三题 A=[[1, 2], [3, 4]]和B=[[5, 6],[7, 8]]矩阵分析

# 创建矩阵
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6],[7, 8]])

# A + B
print(A+B)
# A * B
print(A*B)
# A@B
print(A@B)

第四题 形状(3,4),范围[0,10)随机数组分析

# 随机种子创建随机数组
np.random.seed(0)
arr = np.random.randint(0, 10, (3, 4))
# 每列最大值,axis=0,轴为列
print(np.max(arr,axis=0))
# 每行最小值,axis=1,轴为行
print(np.min(arr,axis=1))
# 将奇数替换为-1
print(np.where(arr%2!=0,arr,-1))

# 布尔索引
arr[arr%2==1]=-1
print(arr)

第五题 数组变形

# 一维形状12数组,转为(3, 4)二维数组
arr = np.arange(1,13,1)
arr = np.reshape(arr, (3,4))

# 每行平均值
print(np.mean(arr,axis=1))
# 每行的和
print(np.sum(arr,axis=1))
# 每列平均值
print(np.mean(arr,axis=0))
# 转为一维数组
arr = np.reshape(arr, (12))
arr = np.reshape(arr, (arr.size))
arr = np.reshape(arr, (len(arr)))

第六题 布尔索引

# 生成形状(5, 5),范围[0, 20)的随机数组
np.random.seed(0)
arr = np.random.randint(0, 20, (5, 5))
# 找出大于10的元素
arr[arr>10]
# 将大于10的替换为0
arr[arr>10]=0
print(np.where(arr > 10, arr, 0))

第七题 统计函数应用

# 题目描述: 6个月销售额[120, 135, 110, 125, 130, 140]
# 生成数组
arr = np.array([120, 135, 110, 125, 130, 140])
# 总和
print(np.sum(arr))
# 均值
print("%.3f"%np.mean(arr))
# 方差
print("%.3f"%np.var(arr))
# 销售额最高月份
print(np.argmax(arr)+1)
# 销售额最第月份
print(np.argmin(arr)+1)

第八题 数组拼接

# 题目描述: A = [1, 2, 3]和B = [4, 5, 6]
# 创建数组
A = np.array([1, 2, 3])
B = np.array([4, 5, 6])
# A和B水平拼接
C = np.concatenate([A,B])
# A和B垂直拼接
print(np.reshapeC,(2,3))

第九题 唯一值与排序

# 创建数组[2, 1, 2, 3, 1, 4, 3]
arr = np.array([2, 1, 2, 3, 1, 4, 3])
# 找出唯一值并排序
print(np.unique(arr))
# 计算每个唯一值出现次数
u_arr,counts = np.unique(arr, return_counts=True)
print(counts)

# for循环实现
counts = []
for i in range(len(u_arr)):
    counts = counts + [len(arr[arr==u_arr[i]]))]

第十题 综合应用

# 题目描述 5天销售额与成本为[20, 25, 22, 30, 28]  [15, 18, 16, 22, 20]
# 创建数组
arr = np.array([20, 25, 22, 30, 28])
arr1 = np.array([15, 18, 16, 22, 20])
# 每天利润
arr2 = arr-arr1
# 利润平均值
np.mean(arr2)
# 利润标准差
np.std(arr2)
# 利润最高的天数
len(arr2[arr2==np.max(arr2)])

# 利润最高是第几天
for i in range(len(arr2)):
    if arr2[i]==np.max(arr2):
        print(i+1)

Pandas

Pandas是数据读取,清洗,分析,统计,输出的高效工具,基于Numpy构建处理表格和混杂数据的python库.

Pandas简介

Series和DataFrame分析
数据类型 Series DataFrame
维度 一维 二维
索引 单索引 行所以+列名
数据存储 同质化数据类型 各列可不同数据类型
类比 Excel单列 整张Excel工作表
创建方法 pd.Series([1, 2, 3]) pd.DataFrame("列标签":{1, 2, 3})

Series

Series类似于Excel单列,有行索引,列标签

Series创建方法

自定义索引,标签创建Series

# 导入pandas包
import pandas as pd
# Series的创建
s = pd.Series([1,2,3,4,5])
0    1
1    2
2    3
3    4
4    5

# 自定义索引,定义标签name
s = pd.Series([1,2,3,4,5], index=['a','b','c','d','e'], name='月份')
a    1
b    2
c    3
d    4
e    5
Name: 月份, dtype: int64

通过字典,Series创建Series

# 通过字典创建
s = pd.Series({'a':1,'b':2,'c':3,'d':4,'e':5}, name='月份')

# 通过series创建
s = pd.Series(s, index=['a','b','c'])
a    1
b    2
c    3
Name: 月份, dtype: int64
Series属性

index索引  values值 dtype/dtypes类型 shape形状 ndim维度 size个数 name标签

数组访问函数   loc[]显示索引   iloc[]隐式索引,位置访问   at[]索引访问    iat[]位置访问

s = pd.Series({'a':1,'b':2,'c':3,'d':4,'e':5}, name='月份')

# 获取索引
print(s.index)
# 获取值
print(s.values)
# 获取数据类型
print(s.dtype)
# 获取标签
print(s.name)
# 获取形状
print(s.shape)
# 获取个数
print(s.size)
# 获取维度
print(s.ndim)
# 获取是否为空
print(s.empty)

# 访问数组函数
# 获取索引a值
print(s.loc['a'])
# 获取索引0值
print(s.iloc[0])
# 获取索引a到c
print(s.loc['a':'c'])
# 获取索引0到2
print(s.iloc[0:2])
# 获取索引a的值
print(s.at['a'])
# 获取索引0的值
print(s.iat[0])
Series查看数据
s = pd.Series({'a':1,'b':2,'c':3,'d':4,'e':5}, name='月份')
# 获取索引a的值
print(s['a'])
# 布尔索引
print(s[s<3])
# 获取前5行
print(s.head())
# 获取前3行
print(s.head(3))
# 获取后5行
print(s.tail())
Series常用方法与统计

查看函数 head() tail() isin() isna()

统计函数 sum() mean() min() max() var() std() median() mode()众数

quantile()分位数  describe()显示常见统计信息(count mean std min 25% 50% 75% max)

排序于唯一值函数  value_counts()唯一值出现次数  count()非缺失值数量

nunique()唯一值个数   unique()去重后值的数组    drop_duplicates()去除重复项  sample()随机抽样   sort_index()索引排序  sort_values()值排序   replace()替换值   keys()返回索引

查看函数

import numpy as np
s = pd.Series({'a':1,'b':2,'c':np.nan,'d':None,'e':5}, name='月份')
# 查看函数
# 获取前3行
print(s.head(3))
# 获取后2行
print(s.tail(2))
# 描述
print(s.describe())
# 获取索引
print(s.keys())
# 获取索引
print(s.index)
# 判断值是否为空
print(s.isna())
# 判断值是否在列表中
print(s.isin([5,1,2]))

统计函数

# 统计函数
s = pd.Series({'a':1,'b':2,'c':np.nan,'d':None,'e':5}, name='月份')
# 获取总和
print(s.sum())
# 获取平均值
print(s.mean())
# 获取中位数
print(s.median())
# 获取众数
print(s.mode())
# 获取标准差
print(s.std())
# 获取方差
print(s.var())
# 获取最小值
print(s.min())
# 获取最大值
print(s.max())
# 获取绝对值
print(s.abs())
# 获取乘积
print(s.prod())
# 获取累加
print(s.cumsum())
# 获取累乘
print(s.cumprod())
# 获取当前最大值
print(s.cummax())
# 获取当前最小值
print(s.cummin())
# 获取个数
print(s.count())
# 获取唯一值的个数
print(s.value_counts())
# 获取最小值和最小值索引
print(s.idxmax())
print(s.idxmin())
# 获取百分位数50%
print(s.quantile(0.5))
# 按值排序,不改变次序
print(s.rank())
# 获取唯一值个数
print(s.nunique())
# 获取唯一值,返回list
print(s.unique())
# 获取一个随机值
print(s.sample())
# 去重,返回Series
print(s.drop_duplicates())
# 按索引排序
prin(s.sort_index())
# 按值排序,改变次序
prin(s.sort_values())
Series案例练习

第一题 学生成绩统计

# 题目描述 10人成绩[50,100]
# 创建Series数组
np.random.seed(42)
values = np.random.randint(0,101,10)
indexs = []
for i in range(1,11):
    indexs.append('学生'+str(i))
scores = pd.Series(values, index=indexs)
# 平均分
print(scores.mean())
# 最高分
print(scores.max())
# 最低分
print(scores.min())
# 高于平均分人数
print(scores[scores>scores.mean()].count())
print(len(scores[scores>scores.mean()]))

第二题 温度分析

# 题目描述 一周温度 [28, 31, 29, 32, 30, 27, 33]
# 创建Series数组
values = [28, 31, 29, 32, 30, 27, 33]
indexs = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
temp = pd.Series(values, index=indexs, name='温度')
# 温度超过30度
print(temp[temp>30])
# 平均温度
print(temp.mean())
# 温度从高到低,升序False
print(temp.sort_values(ascending=False))
# 温度变化最大的两天
# diff前后两元素差
print(temp.diff().abs().nlargest(2))
# 或者
tem = temp.diff().abs()
print(tem.sort_values(ascending=False).keys()[:2].tolist())
print(tem.sort_values(ascending=False).index[:2].tolist())

第三题 股票分析

# 题目描述 10个收盘价
# 创建Series数组
values = [102.3, 103.3, 105.2, 104.1, 106.5, 107.1, 106.3, 108.4, 109.4, 110.5]
indexs = pd.date_range('2023-01-01',periods=10) 
prices = pd.Series(values, index=indexs, name='收盘价')

# 每日收益(当天/前天-1)
tem = prices.pct_change()
# 收益最高日期
print(tem.idmax())
# 收益最低日期
print(tem.idmin())
# 波动率收益标准差
print(tem.std())

第四题 销售数据分析

# 题目描述 12个销售量
values = [120, 135, 145, 160, 155, 170, 180, 175, 190, 200, 210, 220]
indexs = pd.date_range('2025-01-01', periods=12, freq='ME')
sales = pd.Series(values, index=indexs, name='销售量')
# DE按天  WE按周  ME按月  QE按季  YE按年
# 季度平均销售
sales.resample('QS').mean() # Q按季重新采样,平均值
sales.resample('QS').sum() # Q按季重新采样,求和
# 销售最高月份
sales.idxmax()
# 月环比比上月增长量(同比比去年)
sales.pct_change()
# 连续增长超过两个月月份
tem = sales.pct_change()
tem[(tem>0).rolling(3).sum()==3].keys().tolist()

第五题 每小时销售数据分析

# 题目描述 一天24小时销量额
# 创建Series数组
np.random.seed(42)
values = np.random.randint(0,100,24)
indexs = pd.date_range('2025-01-01', periods=24, freq='h')
h = pd.Series(values, index=indexs, name='销售额')

# 按天重采样,每日销售总额
d=h.resample('D').sum()
h.sum()

# 营业时间(8-22)和非营业时间销售额比
# 获取营业时间收益,三种方法
h.between_time('8:00','22:00').sum()
b = h[(h.index.hour>=8)&(h.index.hour<=22)]
mask = (h.index.hour>=8)&(h.index.hour<=22)
b = h[mask]
# 获取非营业时间收益,三种方法
nb = h.drop(b.index).sum()
nb = h[(h.index.hour<8)|(h.index.hour>22)].sum()
nb = h[~mask]
print(b.sum()/nb)

# 销售额最高的3销售
print(h.nlargest(3))

DataFrame

DataFrame类似于Excel整张工作表,有行索引和列名称索引

DataFrame创建方法
import numpy as np
import pandas as pd

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

# 通过字典创建
df = pd.DataFrame({ 'name':["tom", "jack","bob", "qia", "zul"],'age':[18,22,23,14,15],
                    'sex':['male', 'male', 'female', 'male', 'female']},
                    index=[1,2,3,4,5],columns=['name', 'sex', 'age'])

DataFrame属性

index values dtypes shape ndim size columns列标签 loc[] iloc[] at[] iat[] T转置

# 获取DataFrame信息
# 获取索引
print(df.index)
# 获取列标签
print(df.columns)
# 获取数据值
print(df.values)
# 获取行数和列数
print(df.shape)
# 获取数据类型
print(df.dtypes)
# 获取描述信息
print(df.describe())
# 获取转置
print(df.T)
DataFram访问数据
# 获取单列数据
print(df.name)
print(df['name'])
print(df[['name', 'age']])
# 查看部分数据
df.head(3)
df.tail(3)
# 布尔索引
df[(df['age'] > 20) & (df.age < 30)]
# 数据采样
df.sample(3)

# 获取元素
# 通过索引获取行数据
print(df.loc[4])  # 获取key为4数据
print(df.iloc[3])  # 获取第4行数据
# 通过标签获取列数据
print(df.loc[:, 'name'])
print(df.iloc[:, 0])
# 获取单个数据
print(df.at[3, 'name'])
print(df.iat[2,0])
print(df.loc[3, 'name'])
print(df.iloc[2,0])
DataFrame常用方法与统计

isin()   isna()    mode()     quantile()   describe()      drop_duplicates()去重      replace()替换值  sample() 随机采样   resample()重构   nlargest()返回最大n条数据   nsmallest 返回最小n条数据  duplicated()是否重复

# 默认显示前5行
df.head()
df.tail()
# 判断数据是否在集合中
df.isin(['jack',20])
# 检测数据是否为空
df.isna()
# 检测数据是否不为空
df.notna()

# 统计函数
# 求和
df.age.sum()
# 最大值
df['age'].max()
# 最小值
df['age'].min()
# 平均值
df.age.mean()
# 中位数
df.age.median()
# 标准差
df.age.std()
# 方差
df.age.var()
# 众数
df.age.mode()
# 50%分位数
df.age.quantile(0.5)
# 描述信息
df.describe()

# 每列个数
df.count()
# 每列的出现个数
df.value_counts()
# 每列的去重个数,DataFram
df.drop_duplicates()
# 检查是否重复
df.duplicated(subset='age')
# 替换
df.replace(15,16)
# 累加
df.cumsum()
# 累乘
df.age.cumprod()
# 累计最大
df.cummax()
# 每列的去重,list
df.age.unique()
# 每列的去重个数
df.age.nunique()

# 索引排序
df.age.sort_index()
# 值排序
df.sort_values(by=['name','age'],ascending=[True,False])

# 求最大值
df.nlargest(2,columns=['age'])
DataFrame案列练习

第一题 学生成绩分析

# 题目描述 学生成绩数据
data = {'姓名':['张三','李四','王五','赵六', '钱七'],'数学':[85,95,88,78,95],'英语':[90,88,85,92,80],'物理':[75,80,88,85,90]}

# 创建DataFrame
df = pd.DataFrame(data)
# 每位学生总分
df['总分'] =df[['数学','英语','物理']].sum(axis=1)
# 每位学生平均分
df['平均分'] = df[['数学','英语','物理']].mean(axis=1)
# 数学高于90或英语高于85
df[(df['数学']>90)|(df['英语']>85)]
# 总分高到低的前三个
df.sort_values(by='总分',ascending=False).head(3)
df.nlargest(3,'总分')

第二题 销售数据分析

# 题目描述: 销售数据
data = {'产品名称':['A','B','C','D'],'单价':[100,150,200,120],'销量':[50,30,20,40]}
# 创建DataFrame
df = pd.DataFrame(data)
# 每种产品销售额(销售额 = 单价 * 销量)
df['总销售额'] = df[['单价','销量']].prod(axis=1)
# 销售额最高产品
df.nlargest(1,'总销售额')
# 销售额从高到低
df.sort_values(by='总销售额',ascending=False)

第三题 电商分析

# 题目描述 用户行为数据
data = {'用户ID':[101, 102, 103, 104, 105],'用户名':['Tom','Bob','Jack', 'Maike','Lucy'],'商品类别':['电子产品','服饰', '电子产品', '家居', '服饰'],'商品单价':[1200,300,800,150,200],'购买数量':[1,3,2,5,4]}
# 创建DataFrame
df = pd.DataFrame(data)
# 每位用户消费金额(消费金额 = 商品单价 * 购买数量)
df['消费金额'] = df[['商品单价','购买数量']].prod(axis=1)
# 输出消费金额最高用户
df.nlargest(1,'消费金额')
# 所有用户平均消费金额
print('%.2f'%df['消费金额'].mean())
# 电子产品总购买数量
df[df['商品类别']=='电子产品']['购买数量'].sum()

Pandas数据分析

CSV和Excel区别

Excel:结构复杂, 以二进制(.xls)或 XML(.xlsx)格式存储

CSV: 结构简单,格式由逗号(制表符、分号)分隔的纯文本文件


数据导入/导出

CSV数据转成DataFrame导入导出

# CSV数据导入
import pandas as pd
# 将数据读入成DataFrame
df = pd.read_csv(r"data\employees.csv")
# CSV数据导出
df.to_csv(r"data\employees_out.csv", index=False)

Json数据转成DataFrame导入导出

# 简单的json格式数据
df = pd.read_json(r"data\data1.json")
# 复杂的json格式数据
import json
with open(r"data\test.json", "r", encoding="utf-8") as f:
    data = json.load(f)
df = pd.DataFrame(data['users'])

数据处理

缺失值处理 

缺失值查询

# 缺失值查询
import pandas as pd
import numpy as np
s = pd.Series([0, 1, np.nan, 3, 4, np.nan])
print(s.isna())
print(s.isnull())
print(s.isna().sum())
df = pd.DataFrame([[1,pd.NA,2],[2,np.nan,5],[None,4,6],[7,8,9]],columns=['第一列','第二列','第三列'])
print(df.isna())
print(df.isnull())
# 按行统计缺失值
print(df.isna().sum(axis=1))
# 按列统计缺失值
print(df.isna().sum(axis=0))

缺失值类型      np.nan(不是一个值1除以0)       None(空值)        pd.NA(空值) 

缺失值删除

# 删除缺失值
print(s.dropna())
# 删除含缺失值的一整行
print(df.dropna())
# 删除所有值都是缺失值的行
print(df.dropna(how="all"))
# 如果有n个数不是缺失值,就保留
print(df.dropna(thresh=2))
# 删除缺失值所在列
print(df.dropna(axis=1))
# 指定删除某列缺失值
print(df.dropna(subset=['第一列']))

缺失值填充

# 填充缺失值
df = pd.read_csv(r"data\weather_withna.csv") 
df.isna().sum(axis=0)
# 固定值填充,字典填充
print(df.fillna({'temp_max':20, 'wind':2.5}))
# 统计值填充
print(df.fillna(df[['temp_max','wind']].mean()))
# 前向front填充
print(df.ffill())
# 后向back填充
print(df.bfill())
重复数据处理

查询/删除重复数据

# 查询/删除重复数据
data = {
    'name':['Tom','张三','Jack','张三','张三'],
    'age':[20,21,22,21,21],
    'city':['上海','北京','广东','北京','北京']   
}
df = pd.DataFrame(data)
# 一整行重复标记True
print(df.duplicated())
# 删除重复
print(df.drop_duplicates())
# 根据列去重
print(df.drop_duplicates(subset=['name']))
# 保留后面重复数据
print(df.drop_duplicates(subset=['name'],keep='last'))

数据类型转换

# 数据类型转换
df['age'] = df['age'].astype('int16')
# 转为分类
df['gender'] = df['gender'].astype('category')
# map函数映射,转为布尔
df['is_male'] = df['gender'].map({'Male':True,'Female':False})

数据变形

# 数据变形
data = {
    "ID":[1,2],
    "name":["张 三","王 五"],
    'Math':[85,98],
    'English':[92,86],
    'Chinese':[83,99]
}
df = pd.DataFrame(data)

# 转置
df.T

# 宽表转长表
df = pd.melt(df,id_vars=['ID','name'],var_name='subject',value_name='score').sort_values('name')
# 长表转宽表
pd.pivot(df,index=['ID','name'],columns='subject',values='score')

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

# 分裂,数据类型转换案例练习
df = pd.read_csv(r"data\sleep.csv")
df = df[['person_id','blood_pressure']]
df[['high','low',]] = df['blood_pressure'].str.split("/",expand=True)
df.info()
df['high'] = df['high'].astype('int64')
df['low'] = df['low'].astype('int64')
df.high.mean()
df.low.mean()
数据分箱
# 数据分箱pd.cut(x,bins,labels)
import pandas as pd
df = pd.read_csv(r"data\employees.csv")
df = df.head(10)[['employee_id','salary']]

# 对salary分箱,bin表示多少个箱子
pd.cut(df['salary'],bins=2).value_counts()
# 自定义区间
df['收入范围'] = pd.cut(df['salary'],bins=[0,10000,20000,30000],labels=['低','中','高'])
# 等人数分箱
pd.qcut(df['salary'],q=3).value_counts()

分箱练习

# 统计练习
df = pd.read_csv(r"data\sleep.csv")
df = df.head(10)[['person_id','gender','sleep_quality']]
# 数值统计先分箱
df['睡眠质量'] =pd.cut(df['sleep_quality'],bins=3,labels=['差','中','好'])
df['睡眠质量'].value_counts()
# 字符串统计
df['gender'] = df['gender'].astype('category')
df['gender'].value_counts()

# 转换函数 rename() set_index() reset_index
df = pd.DataFrame({'name':['Tom','Jack','July'],'age':[20,21,22],'gender':['Male','Male','Female']})
# 设置索引
df.set_index('name',inplace=True)
# 重置索引
df.reset_index(inplace=True)
# 重命名列名与索引
df.rename(columns={'name':'姓名'},index={0:4},inplace=True)
df.index=[0,1,2]
df.columns = ['姓名','年龄','性别']
时间数据处理

时间戳相关属性

# 时间戳
import pandas as pd
d = pd.Timestamp('2019-01-01 10:22')
# 获取时间戳信息
print(d.date)

# 获取时间戳的年月日时分秒
print(d.year)
print(d.month)
print(d.day)
print(d.hour)
print(d.minute)
print(d.second)

# 获取时间戳的季度
print(d.quarter)
# 获取时间戳的星期几
print(d.day_name())
# 判断时间戳是否是月初
print(d.is_month_start)
# 获取时间戳是否是月末
print(d.is_month_end)
# 转换为天数
print(d.to_period("D"))
# 转换为季度
print(d.to_period("Q"))

转换时间戳数据类型

# 字符串转换为时间戳
d = pd.to_datetime('20250607220620')

# dataFrame转换为时间戳
df = pd.DataFrame({'sales':[10,20,30],'date':["20250607","20250608","20250609"]})
df['datetime']=pd.to_datetime(df['date'])
# 查看数据类型信息
print(df.info())
# dt列表的时间选择器
print(df['datetime'].dt.day_name())

# CSV日期转换
df = pd.read_csv(r"data\weather.csv",parse_dates=['date'])
# 方法一,parse_dates自动解析转换
df['date'].dt.day_name()
# 方法二,pd.to_datetime()类型转换
df['datetime'] = pd.to_datetime(df['date'])
df['datetime'].dt.day_name()

时间戳索引并访问

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

时间间隔delta

# 时间间隔
d1 = pd.Timestamp('2017-06-07')
d2 = pd.Timestamp('2023-06-07')
# 获取时间间隔
d3 = d2-d1
# 获取时间隔做索引访问
df["delta"] = df['date'] - df['date'][0]
df.set_index(["delta"], inplace=True)
print(df.loc['0 days':'9 days'])

时间序列创建

# 创建时间序列
# 以频率freq从start到end创建
days = pd.date_range(start='2019-01-01',end='2019-01-31',freq='D')
# 以频率freq从start创建31个元素
days = pd.date_range('2019-01-01',periods=31,freq='D')

重采样

# 重采样
df = pd.read_csv(r"data\weather.csv",parse_dates=['date'])
df.set_index('date',inplace=True)
# 对temp_max和temp_min重采样,取平均
df[['temp_max','temp_min']].resample('YE').mean()
分组聚合
# 分组聚合df.groupby('分组的字段')['聚合的字段'].聚合函数
df = pd.read_csv(r"data\employees.csv")
# 检查缺失值
print(df['department_id'].isna().sum())
# 删除缺失值
df.dropna(subset=['department_id'],inplace=True)
# id从float转为int
df['department_id']=df['department_id'].astype('int64')

# 不同部门平均工资
# 查看分组
df.groupby('department_id').groups
# 查看具体分组数据
df.groupby('department_id').get_group(10)
# 聚合
df = df.groupby('department_id')[['salary']].mean()
# 保留两位小数
df['salary'] = df['salary'].map('{:.2f}'.format)
df['salary'] = df['salary'].round(2)
df.reset_index(inplace=True)
# 排序输出
df.sort_values('salary',ascending=False,inplace=True)

# 分组聚合练习
df = pd.read_csv(r"data\employees.csv")
# 不同部门不同岗位平均薪资
df = df.groupby(['department_id','job_id'])[['salary']].mean().round(1).sort_values('salary',ascending=False).reset_index()

数据分析案例练习

数据分析步骤  1.导包 2.数据导入 3.数据清洗 4.数据特征构造 5.数据分析 6.数据可视化

题目一 企鹅数据分析
# 1.导包
import pandas as pd
# 2.数据导入
df = pd.read_csv(r"data\penguins.csv")
df.head()
df.info()

# 3.数据清洗
# 缺失值检查
print(df.isna().sum())
df.dropna(inplace=True)
len(df)

# 4.数据特征构造
# 性别数据类型转换为类别
df['sex'] = df['sex'].astype('category')
# 喙的长宽比
df['bill_ratio'] = df['bill_length_mm']/df['bill_depth_mm']

# 5.数据分析
# 数据分箱,分为三个等级
df['mass_level'] = pd.cut(df['body_mass_g'],bins=3,labels=['低','中','高'])
# 体重各级数量
df['mass_level'].value_counts()

# 按岛屿,性别分组分析
df.groupby(['island','sex']).agg({'body_mass_g':['mean','count']})
第二题 睡眠质量分析
# 1.导包
import pandas as pd
# 2.数据导入
df = pd.read_csv(r"C:\Users\16774\Downloads\课件及代码\课件及代码\代码\data\sleep.csv")
df.head()
df.info()
df.describe()

# 3.数据清洗
# 缺失值检查
print(df.isna().sum())
df['sleep_disorder'].value_counts()
df.drop(columns='sleep_disorder',inplace=True)

# 4.数据特征构造
# 类型转换
df['gender'] = df['gender'].astype('category')
df['occupation'] = df['occupation'].astype('category')
df['bmi_category'] = df['bmi_category'].astype('category')
df[['high','low']] = df['blood_pressure'].str.split('/',expand=True)

# 睡眠质量分箱
df['quality_level'] = pd.cut(df['sleep_quality'],bins=3,labels=['差','中','优'])
# 年龄分箱
df['age_level'] = pd.cut(df['age'],bins=3,labels=['青少年','中年','老年'])

# 5.数据分析
# 查看bin类型数
print(df['bmi_category'].value_counts())
# 根据age_level,bim分组的睡眠质量
df.groupby(['age_level','bmi_category']).agg({'sleep_quality':['mean'],'stress_level':['mean']})

数据可视化

可视化作用 分析趋势 发现错误 突出对比

绘图要素  标题  坐标轴  图形  图例  数据标签

可视化工具   Matplotib灵活基础    Seaborn美观繁琐    Pandas可视化-快捷样式简单

图形 折线图plot 柱状图bar 条形图barh 饼图pie 散点图scatter 箱型图boxplot

折线图-趋势

# 绘制折线图
# 导入matplotlib包
import matplotlib.pyplot as plt
# 导入字体rcParams包
from matplotlib import rcParams
# 设置字体
# 方法一
rcParams['font.family'] = 'SimHei'
# 方法二
rcParams['font.sans-serif'] = ['SimHei']
# 创建图标,设置大小
plt.figure(figsize=(10,5))

month = ['1月','2月','3月','4月','5月']
sales = [100,150,300,250,500]
# 绘制折线图
plt.plot(month,sales,label='产品A',color='blue',linewidth=2,linestyle='-',marker='o')
# 设置标题
plt.title('2025年销售趋势', fontsize=20, color='blue')

# 添加标签
plt.xlabel('月份', fontsize=15, color='black')
plt.ylabel('销售额(万元)', fontsize=15, color='black')

# 添加图例
plt.legend('销售额(万元)', loc='upper left')
plt.legend('销售额(万元)', loc='lower right')

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

# 设置刻度字体大小,与旋转
plt.xticks(fontsize=15,rotation=0)
plt.yticks(fontsize=15,rotation=0)
# 设置y轴范围
plt.ylim(0,600)

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

# 显示图形
plt.show()

柱状图-对比

柱状图代码与折线图相似  width控制宽度,没有marker属性

# 绘制柱状图
plt.bar(subjects,scores,label='成绩',color='blue',width=0.6)

条形图代码与柱状图相似 先传y轴,后传x轴,端点值显示注意yx顺序

# 绘制条形图
plt.barh(countries,gdp,label='GDP',color='blue')

# 每个数据点上显示数值,注意yx顺序
for y,x in zip(countries,gdp):
    plt.text(x,y,f'{x}',ha='left',va='center',fontsize=15)

饼图-组成占比

数据准备

# 饼图
# 导入matplotlib包
import matplotlib.pyplot as plt
# 导入字体rcParams包
from matplotlib import rcParams
# 设置字体
# 方法一
rcParams['font.family'] = 'SimHei'
# 方法二
rcParams['font.sans-serif'] = ['SimHei']
# 创建图标,设置大小
plt.figure(figsize=(10,5))

things = ['学习', '睡觉', '工作', '娱乐', '运动']
times = [5, 8, 5, 2, 4]

绘制饼图

# 绘制饼图
plt.pie(times,labels=things,autopct='%.1f%%',startangle=90,colors=['#66b3ff','#ff9999', '#99ff99', '#ff4499', '#c2c2f0']shadow=True)

绘制环形图

# 绘制环形图,wedgeprops占半径百分比,pctdistance占比数离原点距离
plt.pie(times,labels=things,autopct='%.1f%%',startangle=90,colors=['#66b3ff','#ff9999', '#99ff99', '#ff4499', '#c2c2f0'],wedgeprops={'width':0.5},pctdistance=0.6,shadow=True)

标题/图例

# 设置标题
plt.title('一天时间分配', fontsize=20, color='blue')

# 添加图例,1.05超出右边界5%,1与上边界对齐
plt.legend(['学习', '睡觉', '工作', '娱乐', '运动'], bbox_to_anchor=(1.05, 1))

散点图-相关性

# 绘制散点图
# 导入matplotlib包
import matplotlib.pyplot as plt
# 导入字体rcParams包
from matplotlib import rcParams
import random
# 设置字体
# 方法一
rcParams['font.family'] = 'SimHei'
# 方法二
rcParams['font.sans-serif'] = ['SimHei']
# 创建图标,设置大小
plt.figure(figsize=(10,6))

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

# 绘制散点图
plt.scatter(x,y,label='映射',color='blue',alpha=0.5,s=20)
# 设置标题
plt.title('x与y变量映射', fontsize=20, color='blue')

# 添加标签
plt.xlabel('x变量', fontsize=15, color='black')
plt.ylabel('y变量', fontsize=15, color='black')

# 添加图例
plt.legend('映射', loc='upper left')
plt.legend('映射', loc='lower right')

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

# 设置刻度字体大小,与旋转
plt.xticks(fontsize=15,rotation=0)
plt.yticks(fontsize=15,rotation=0)
# 设置y轴范围
plt.ylim(0,30)
# 绘制直线两个横坐标[0,10],两个纵坐标[0,20]
plt.plot([0,10],[0,20],color='orange',linewidth=2)
# 每个数据点上显示数值
# for x,y in zip(x,y):
#     plt.text(x,y,str(y),ha='center',va='bottom',fontsize=15)

# 显示图形
plt.show()

箱线图-数据分布与异常

IQR=Q3-Q1  上边缘Q3+1.5*IQR  下边缘Q3-1.5*IQR   异常值,超出上边缘和下边缘

# 导包 
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'SimHei'

# 数据准备
data = {
    '语文': [80, 90, 85, 95, 80, 90, 85, 95, 72, 90, 85, 95],
    '数学': [75, 85, 90, 80, 75, 85, 90, 80, 75, 85, 90, 80],
    '英语': [90, 85, 95, 80, 90, 85, 95, 80, 90, 85, 95, 80],
}
# 准备画布
plt.figure(figsize=(10, 6))
# 绘图
plt.boxplot(data.values(),tick_labels=data.keys())
# 标题
plt.title("各科成绩")
# 坐标标签
plt.xlabel('分数')
plt.ylabel('科目')
# 网格
plt.grid(True,axis='y',alpha=0.3,color='black',linestyle='--')
# y范围
plt.ylim(70,100)

# 显示
plt.show()

多个图的绘制方法

# 多个图的绘制方法
import matplotlib.pyplot as plt
month=['1','2','3','4']
sales=[100,150,80,130]

# 创建子图,行列索引
f1=plt.subplot(2,2,1)
f1.plot(month,sales)
f2=plt.subplot(222)
f2.bar(month,sales)
f3=plt.subplot(2,2,3)
f3.scatter(month, sales)
f4 = plt.subplot(2,2,4)
f4.barh(month, sales)

绘图案例练习

# 绘图案例练习
# 题目 温度分析
import matplotlib.pyplot as plt
from matplotlib import rcParams
import pandas as pd
# 1.设置字体
rcParams['font.family'] = 'SimHei'

# 2.导入数据
df = pd.read_csv(r'C:\Users\16774\Downloads\课件及代码\课件及代码\代码\data\weather.csv')
df.head()
# 绘制气温的趋势变化图
df['date'] = pd.to_datetime(df['date'])
df = df[df['date'].dt.year == 2015]
df.info()
# 最高,最低气温的趋势变化图
plt.figure(figsize=(10,10))
plt.plot(df['date'],df['temp_max'],label='最高气温')
plt.plot(df['date'],df['temp_min'],label='最低气温')
plt.title('2015年气温变化趋势')
plt.xlabel('月份')
plt.ylabel('气温')
plt.legend()

# 绘制平均气温的趋势变化图
df['temp_mean'] = (df['temp_max'] + df['temp_min']) / 2
plt.figure(figsize=(10,10))
plt.plot(df['date'],df['temp_mean'],label='平均气温')
plt.title('2015年平均气温变化趋势')
plt.xlabel('月份')
plt.ylabel('气温')
plt.legend()

# 绘制降水量直方图
plt.figure(figsize=(10,10))
# 绘制直方图,分箱绘制
plt.hist(df['precipitation'],bins=5)
plt.title('2015年降水量直方图')
plt.xlabel('降水量')
plt.ylabel('频数')
plt.show()

seaborn-各图形绘制

导包数据准备

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

# 设置字体
rcParams['font.family'] = 'SimHei'
penguins = pd.read_csv(r'C:\Users\16774\Downloads\课件及代码\课件及代码\代码\data\penguins.csv')
penguins.dropna(inplace=True)
penguins.info()
penguins.head()

直方图 箱线图 散点图 点图 条形图 核密度估计图 估计图

# 直方图
sns.histplot(data=penguins,x='species')
# 绘制箱线图
sns.boxplot(data=penguins,x='species',y='flipper_length_mm')
# 散点图
sns.scatterplot(data=penguins,x='bill_length_mm',y='bill_depth_mm',hue='species')
# 绘制点图
sns.pointplot(data=penguins,x='species',y='flipper_length_mm')
# 绘制条形图
sns.barplot(data=penguins,x='species',y='flipper_length_mm')
# 核密度估计图
sns.kdeplot(data=penguins,x='flipper_length_mm')
# 估计图
sns.ecdfplot(data=penguins,x='flipper_length_mm')

直方图+核密度估计图

# 直方图+核密度估计
sns.histplot(data=penguins,x='bill_length_mm', kde=True)

计数图  蜂窝图  二维核密度估计图  成对关系图

# 计数图,适应不连续区间,与直方图类似
sns.countplot(data=penguins,x='island')

# 蜂窝图
sns.jointplot(data=penguins,x='body_mass_g',y='flipper_length_mm',kind='hex')

# 二维核密度估计图
sns.kdeplot(data=penguins,x='body_mass_g',y='flipper_length_mm')

# 成对关系图
sns.pairplot(data=penguins,hue='species')

实战练习

数据分析流程

采集数据->确定分析方向->导入数据->数据清洗->数据分析->数据可视化

一 数据类型

字段名

含义

说明

city

城市

房屋所在的城市名称,例如“合肥”、“重庆”等。

address

详细地址

房屋的具体位置,包含街道、交叉口等信息。

area

面积

房屋的面积,单位为平方米(㎡)。

floor

楼层

房屋所在的楼层信息,例如“中层(共18层)”。

name

小区名称

房屋所在的小区或楼盘名称。

price

价格

房屋的总价,单位为“万”或“元”。

province

省份

房屋所在的省份或直辖市名称。

rooms

户型

房屋的户型结构,例如“3室2厅”。

toward

朝向

房屋的朝向,例如“南北向”、“南向”等。

unit

单价

房屋的单价,单位为“元/㎡”。

year

建造年份

房屋的建造年份,例如“2013年建”。

origin_url

原始链接

房屋信息的来源网页链接。

二 分析方向

编号

问题

分析主题

分析目标

分组字段

指标/方法

A1

哪些变量最影响房价?面积、楼层、房间数哪个影响更大?

特征相关性

了解房屋各特征对房价的线性影响

皮尔逊相关系数

A2

全国房价总体分布是怎样的?是否存在极端值?

描述性统计

概览数值型字段的分布特征

平均数/中位数/四分位数/标准差

A3

哪些城市房价最高?直辖市与非直辖市差异如何?

城市对比

比较不同城市房价水平

city

均价/单价中位数/箱线图

A4

高价房在面积、楼层等方面有什么特征?

价格分层

识别不同价位房屋特征差异

价格分段(低中高)

列联表/卡方检验

A5

哪种户型最受欢迎?三室比两室贵多少?

户型分析

分析不同户型的市场表现

rooms

占比/平均单价/溢价率

A6

南北向是否真比单一朝向贵?贵多少?

朝向溢价

评估不同朝向的价格差异

toward

方差分析/多重比较

A7

新房比10年老房贵多少?折旧规律如何?

楼龄效应

研究建筑年份对房价的影响

year分段(5年间隔)

趋势线/回归分析

A8

哪些区域交易最活跃?新区和老城区哪个更贵?

区域热度

识别各城市热门交易区域

address(提取区域关键词)

交易量/价格增长率

A9

哪个面积段的性价比最高?超大户型有溢价吗?

面积区间

分析不同面积段的价格特征

area分段(50㎡间隔)

密度图/价格梯度

A10

中层真的比高层贵吗?差价是多少?

楼层差异

比较不同楼层的价格表现

floor(高中低层)

Kruskal-Wallis检验

A11

直辖市房价是否显著更高?单价和总价差异如何?

直辖市vs非直辖市

对比直辖市与非直辖市的房价差异

province

独立样本t检验/曼-惠特尼U检验

三 练习

1 导入库
# 1.导入库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib import rcParams
rcParams['font.sans-serif'] = ['SimHei']
2 导入数据
# 导入数据
df = pd.read_csv(r"data\house_sales.csv")
3 数据概览
# 数据概览
# 总记录数
print(len(df))
# 列数
print(len(df.columns))
# 数据信息
df.head()
df.info()
4 数据清洗

缺失值 重复值 异常值

# 检查是否有缺失值
df.isna().sum()
df.dropna(inplace=True)
# 检查是否有缺失值
df.duplicated().sum()
df.drop_duplicates(inplace=True)
print(len(df))


# 面积数据类型转换
df['area'] = df['area'].str.replace('㎡', '').astype(float)
# 售价数据类型转换
df['price'] = df['price'].str.replace('万', '').astype(float)
# 朝向数据类型转换
df['toward'] = df['toward'].astype('category')
# 单价数据类型转换
df['unit'] = df['unit'].str.replace('元/㎡','').astype('float')
# 建造类型年数据类型转换
df['year'] = df['year'].str.replace('年建', '').astype('int')

# 异常值处理
# 房屋面积的异常处理
df = df[(df['area']<600)&(df['area']>20)]
# 售价的异常处理
Q1 = df['price'].quantile(0.25)
Q3 = df['price'].quantile(0.75)
IQR = Q3 - Q1
df = df[(df['price']>Q1-1.5*IQR)&(df['price']<Q3+1.5*IQR)]
5 新数据特征构造
# 地区district
df['district'] = df['address'].str.split('-').str[0]

# 楼层的类型floor_type
# df['floor_type'] = df['floor'].str.split('(').str[0]
def fun1(str1):
   if pd.isna(str1):
       return '未知'
   elif '低' in str1:
       return '低楼层'
   elif '中' in str1:
       return '中楼层'
   elif '高' in str1:
       return '高楼层'
   else:
       return '未知'
df['floor_type2'] = df['floor'].apply(fun1).astype('category')

# 是否直辖市zxs
# def fun2(str2):
#     return True if str2 in ['北京', '上海', '天津', '重庆'] else False
df['zxs'] = df['city'].apply(lambda x: 1 if x in ['北京', '上海', '天津', '重庆'] else 0)

# 卧室数量bedrooms
df['bedrooms'] = df['rooms'].str.split('室').str[0].astype(int)

# 客厅数量livingrooms
# df['livingrooms'] = df['room'].str.split('室').str[1].str.split('厅').str[0].astype(int)
# 正则表达式
df['livingrooms'] = df['rooms'].str.extract(r'(\d+)厅').astype(int)

# 楼龄building_age
df['building_age'] = 2025 - df['year']

# 价格分段price_labels
df['price_labels'] = pd.cut(df['price'], bins=4, labels=['低价', '中价', '高价', '豪华'])
6 问题分析和可视化 

问题A1 - 特质相关性 哪些变量最影响房价?面积、楼层、房间数哪个影响更大?

皮尔逊相关系数

# 选择数值型特征
# 数值间的相关性
a = df[['price', 'area', 'unit', 'building_age']].corr()
a['price'].sort_values(ascending=False)[1:]
# 绘制相关性矩阵
plt.figure(figsize=(10, 6))
sns.heatmap(a, annot=True, cmap='coolwarm')
plt.title('房屋特征相关性矩阵')
# 自适布局
plt.tight_layout()

问题A2 - 描述性统计  全国房价总体分布是怎样的?是否存在极端值?

# 房价分布直方图
plt.figure(figsize=(10, 6))
# 方法一
plt.hist(df['price'], bins=6)
# 方法二
sns.histplot(df['price'], bins=6, kde=True)

问题A6 - 朝向溢价 南北向是否真比单一朝向贵?贵多少?

# 数据准备
df['toward'].value_counts()
df.groupby('toward').agg({
    'price': ['mean','median'],
    'unit': 'median',
    'building_age':'mean'
})
# 数据可视化
plt.figure(figsize=(10, 6))
sns.boxplot(x='toward', y='price', data=df)
plt.tight_layout()

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐