关于python数据分析,这里提三个最常用的库:numpy,pandas,matplotlib
简单讲一下:
numpy:用于科学计算的库;矩阵运算/线性代数运算/傅里叶变换等,提供多维数组的运算服务,可以直接读硬盘上的数据
pandas:提供数据结构的库;核心结构:Series(一维),DataFrame(二维,比较常用);多用于数据清洗,数据格式转化
matplotlib:提供数据可视化功能;包含多种类型的作图样式;提供了一整套和MATLAB类似的绘图API,非常适合交互式绘图
具体工作流程:
NumPy 是基础层
-
提供了高效的多维数组(ndarray)对象
-
是 Pandas 和 Matplotlib 的底层依赖
-
负责数值计算和数组操作
Pandas 是数据处理层
-
基于 NumPy 构建,使用 NumPy 数组作为底层存储
-
提供了更高级的数据结构(一维Series、二维DataFrame)
-
专注于数据清洗、整理和分析
Matplotlib 是可视化层
-
依赖于 NumPy 的数据结构
-
能够直接处理 Pandas 的数据对象
-
负责将数据转化为直观的图表
Numpy具体使用:
主要方法np.array()创建多维数组实例
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
temp = list((1,2,3,4,5))
arr = np.array(temp)#使用.array创建一维数组
print(temp,arr,arr.ndim,arr.shape) # 输出维度和形状
two_division = np.array([[1, 2, 3], [4, 5, 6]]) #创建多维数组
print(two_division,two_division.ndim,two_division.shape)
#特殊数组 全0数组 全1数组 指定规模 二维以上的规模需要以tuple格式传入
zero_arr = np.zeros((3,4))
one_arr = np.ones((3,4))
print(zero_arr,one_arr)
#按照范围&等差条件创建数组
#创建范围&等差数组
arr3 = np.arange(1,10,step=2) #左闭右开 不包含stop step设置步长
print(arr3,arr3.ndim,arr3.shape)
#等差数组 指定范围 个数 左右都是闭区间
arr4 = np.linspace(start=1,stop=9,num=5)
print(arr4,arr4.ndim,arr4.shape)
#随机数创建
np.random.seed(0) #设置随机数种子 设置后随机数生成不变 保证可复现
"""
返回来自“离散均匀”分布的随机整数
在“半开”区间内指定的dtype(“低”、“高”)。如果
“高”是无(默认值),则结果来自[0,“低”)。
"""
my_random = np.random.randint(10,100,5)
print(my_random)
"""
.rand()
创建一个给定形状的数组,并填充
来自均匀分布的随机样本
定义在“[0, 1)”上。
"""
my_random = np.random.rand(2,3)
print(my_random,my_random.ndim,my_random.shape)
"""
.randn() 返回标准正态分布样本
如果提供正int_like参数,'randn' 生成一个数组
形状为“(d0, d1, ..., dn)”,填充
随机从单变量“正规”(高斯)中抽样
均值为0,方差为1。随机采样的单个浮点
如果没有参数,则返回来自分布。
"""
my_random = np.random.randn(2,3)
print(my_random,my_random.ndim,my_random.shape)
和array属性&形状相关的操作:
array的运算and线性代数基础:
元素计算部分和python基础语法一致,使用+-*/等运算符;
矩阵乘法流程
1. 维度匹配检查
-
矩阵 A 的维度:m × k (m行, k列)
-
矩阵 B 的维度:k × n (k行, n列)
-
关键条件:A的列数(k)必须等于B的行数(k)
-
结果矩阵 C 的维度:m × n
2. 计算公式
结果矩阵 C 的每个元素计算如下:

import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])
print("数组a:", a)
print("数组b:", b)
# 算术运算 同样可以使用np中的方法实现
print("加法:", a + b)
print("减法:", a - b)
print("乘法:", a * b)
print("除法:", a / b)
print("整除:",a//b)
print("幂运算:", a ** 2)
# 比较运算 返回bool
print("大于比较:", a > 2)
print("等于比较:", a == b)
#区分元素乘法*和矩阵乘法@
# 矩阵乘法 线性代数计算
matrix_a = np.array([[1, 2], [3, 4]])
matrix_b = np.array([[5, 6], [7, 8]])
print("矩阵乘法:\n", np.dot(matrix_a, matrix_b))
#也可以使用符合 @ 以及np.ma
print(np.dot(a,b))
print(np.matmul(matrix_a,matrix_b))
print(matrix_a@matrix_b)
#输出如下
"""
数组:
[[1 2 3]
[4 5 6]
[7 8 9]]
总和: 45
每列总和: [12 15 18]
每行总和: [ 6 15 24]
平均值: 5.0
标准差: 2.581988897471611
方差: 6.666666666666667
最小值: 1
最大值: 9
最小值索引: 0
最大值索引: 8
"""
常用的numpy统计计算方法:
sum():求和
mean():求均值
std():standard deviation 标准差
var():variance 方差
min(),argmin():最小值 最小值索引
max(),argmax():最大值,最大值索引
import numpy as np
arr = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# np中的方法 array作为参数传入
print("数组:\n", arr)
print("总和:", np.sum(arr)) #所有元素
print("每列总和:", np.sum(arr, axis=0)) # 沿列方向
print("每行总和:", np.sum(arr, axis=1)) # 沿行方向
print("平均值:", np.mean(arr))
print("标准差:", np.std(arr))
print("方差:", np.var(arr))
print("最小值:", np.min(arr))
print("最大值:", np.max(arr))
print("最小值索引:", np.argmin(arr))
print("最大值索引:", np.argmax(arr))
"""
总和: 45
每列总和: [12 15 18]
每行总和: [ 6 15 24]
平均值: 5.0
标准差: 2.581988897471611
方差: 6.666666666666667
最小值: 1
最大值: 9
最小值索引: 0
最大值索引: 8
"""
numpy中常见的元素分类方法:
where():二分类条件筛选(可嵌套)适用于简单情况;格式where(判断条件,True时的return,False的return)
select():多条件分类 适用于多条件的复杂分类情况;需要传入两个参数condition和choice,并且分类数量和结果数量需要对应
digitize():分箱 适用于数值分类;bins分箱边界左开右闭
unique():用于去重,并自动分配序号;得到 唯一值+分类统计;核心codes, uniques = np.unique(arr, return_inverse=True),其中return_inverse=True用于返回原始数组中每个元素在唯一值数组中的索引位置。
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
# 单条件:大于3为1,否则为0
result = np.where(arr > 3, 1, 0)
# 结果: [0, 0, 0, 1, 1]
# 多条件嵌套 不如select简洁高效
result = np.where(arr < 2, '低',
np.where(arr < 4, '中', '高'))
# 结果: ['低' '中' '中' '高' '高']
arr = np.array([15, 25, 35, 45, 55])
conditions = [
arr < 20,
(arr >= 20) & (arr < 40),
arr >= 40
]
choices = ['青年', '中年', '老年']
result = np.select(conditions, choices, default='未知')
# 结果: ['青年' '中年' '中年' '老年' '老年']
data = np.array([0.2, 1.5, 3.0, 4.5, 6.0])
bins = np.array([0, 1, 2, 3, 4, 5]) # 区间边界 左开右闭
# 返回每个元素所属的箱子索引(从1开始)
indices = np.digitize(data, bins)
# 结果: [1, 2, 4, 5, 6]
# 0.2在[0,1)→1, 1.5在[1,2)→2, 3.0在[3,4)→4... 最右侧bin是num>=5
arr = np.array(['A', 'B', 'A', 'C', 'B', 'A'])
# 获取唯一值
unique_vals = np.unique(arr) # ['A' 'B' 'C']
# 返回每个元素的类别编码
codes, uniques = np.unique(arr, return_inverse=True)
# codes: [0 1 0 2 1 0] (A=0, B=1, C=2)
# uniques: ['A' 'B' 'C']
numpy广播:
示例:
import numpy as np
#数组广播的本质,将运算数组的shape变为相同后运算(不足则自身补齐)保证每一个元素都参与运算
# 广播示例
a = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
b = np.array([10, 20, 30])
print("数组a:\n", a)
print("数组b:", b)
print("广播加法:\n", a + b) # b被广播到a的每一行
# 另一个广播例子
c = np.array([[1], [2], [3]]) #单个的[]表示一行 这里表示的是三行一列(本质二维数组)
print("数组c:\n", c)
print("广播乘法:\n", a * c) # c被广播到a的每一列 c->(3,1)->(3,3)
pandas具体使用:
首先要了解pandas中的两种数据结构:一维的Series 二维的DataFrame;
一般来说,series直接使用list来创建
DataFrame可以使用List[List[]]数据来创建,但更多时候使用dict数据来创建,好处是字典的键值可以直接作为dataframe的列索引
import pandas as pd
import numpy as np
#pandas中的数据结构有两种 一维Series 二维DataFrame
#方法1:通过列表list创建
s1 = pd.Series(data=[1,3,5,7,np.nan,9],index=['a','b','c','d','e','f'],name='score') #允许存在空值
print(s1,type(s1))
print(s1.values,s1.shape,s1.ndim,s1.dtype)
#方法2:通过字典创建
s2 = pd.Series(data={'a':1,'b':2,'c':3},name='score')#传入的dict包含了data和index
print(s2)
#dataframe的创建、
#方法1:通过列表list创建
data_list = [
['张三', 25, '北京', 5000],
['李四', 30, '上海', 7000],
['王五', 35, '广州', 6000],
['赵六', 28, '深圳', 8000]
]
s3 = pd.DataFrame(data=data_list,columns=['姓名', '年龄', '城市', '工资'],index=['a','b','c','d']) #允许存在空值
print(s3,type(s3))
print(s3.values,s3.shape,s3.ndim,s3.dtypes)# z注意 dataframe使用的是dtypes series使用的是dtype
#方法2:通过字典创建
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 35, 28],
'城市': ['北京', '上海', '广州', '深圳'],
'工资': [5000, 7000, 6000, 8000]
}
s4 = pd.DataFrame(data) #取keys作为column
print(s4,type(s4))
pandas文件读取,以DataFrame数据结构为例:
import pandas as pd
path = r'D:\PROJECT\itheima_day9\stu.csv'
df = pd.read_csv(path,names=['姓名', '年龄', '城市', '工资'])
print(df)
print(type(df))
print(df.ndim,df.shape,df.size)
print(df.values) #除了字段名column外的内容
print(df.index) # [0,4) step=1
print(df.dtypes) #获取各个字段的类型
print('='*20)
print(df.head())
print(df.tail())
print(df.describe())
df.info() # 无返回值 调用即输出
print('='*20)
print(df['姓名'],type(df['姓名']))
print(df[['姓名','年龄']],type(df[['姓名','年龄']])) #提取两个column bool表达式
print(df[df['姓名']=='张三']) #内部本质是一个bool表达式,帮助dataframe提取所有匹配值
pandas的数据条件查询and排序查询:
常用的几个方法:
df[:].where() #填写条件查询语句
df[:].query() #同上
当然也可以使用bool表达式;
df[:].sort_values(by='',ascending=True) # 指定排序字段 设定升序/降序
import pandas as pd
path = r'D:\PROJECT\itheima_day9\stu.csv'
df = pd.read_csv(path,names=['姓名', '年龄', '城市', '工资'])
print(df)
print(df[['姓名','工资']].where(df['工资']>5000))
print(df.query('工资>5000 and 姓名=="王五"'))
#排序查询 使用df.sort_values()
print(df.sort_values(by='工资',ascending=False)) # 指定排序字段 设定升序/降序
pandas聚合查询:
常用工具:
len()
.count() #不计入NaN
max(),min(),mean(),sum()
重点:
.groupby(),填入分组字段进行分组操作;
.agg()批量执行聚合操作,避免多次分组/手动合并
df.pivot_table(index:[],columns:[],values='',aggfunc=[]):透视表.pivot_table(),其中index和columns参数都是用于分组的,唯一差别就是index分组索引是横向展示的(以行为单位),columns则是纵向展示(以列为单位),values是需要计算/聚合的字段(支持传入多字段,以list[]形式传入),aggfunc中传入聚合方法;
#聚合查询
print(len(df)) #获取数据条数/员工数量 df.shape[0]也可以
print(df['姓名'].count())
#查询最值
print(df['工资'].max())
print(df[df['工资']==df['工资'].max()])
#平均
print(df['工资'].mean())
#求和
print(df['工资'].sum())
print(df.groupby('城市')['工资'].mean())
#各部门的最高 最低 总包 平均薪资 ((列名即函数名))
print(df.groupby('城市')['工资'].agg(['max','min','sum','mean']))
#agg是用于聚合计算的方法 对分组后的数据进行多统计量一次性计算 agg中直接填写聚合函数名称
#也支持自定义列名
#透视表
print("\n数据透视表:")
pivot_df = df.pivot_table(index=['产品', '地区'], values="销售额", aggfunc=['sum', 'mean'])
print(pivot_df)
"""
print(pivot_df)
df.groupby('部门')['工资'].agg({
'最高薪资': 'max',
'最低薪资': 'min',
'平均薪资': 'mean'
})
对比:不用 agg,需要多次 groupby 或手动合并
max_sal = df.groupby('城市')['工资'].max()
min_sal = df.groupby('城市')['工资'].min()
sum_sal = df.groupby('城市')['工资'].sum()
mean_sal = df.groupby('城市')['工资'].mean()
"""
#groupby() 支持多字段分组 导入参数形式为list
pandas 缺失值处理:
常用方法:
df.isnull(),返回各个字段下缺失值的个数,可以和.sum()配合进行求和,或者/len(df)计算缺失值占比;
df.drop(labels='',axis=1,inplace=True) 对于labels参数传递的列,如果该列中存在NaN,则删除该列(axis=1表示对列进行操作),完成后返回一个处理好dataframe;inplace参数决定是否修改原dataframe的结构(True则修改,后续几个dropna操作仅作展示用,所以不设置inplace参数)
df.dropna(how='',subset=['']) how参数可选:'any','all',分别表示存在任意NaN即删除、该行全为NaN才删除;subset['']参数中填写指定的列名(字段),删除对应字段为NaN的行
df.fillna(value=df.mead()) 对于该列的缺失值,使用该列的均值进行填充
df.ffill() 向前填充:使用前一个有效值,头部NaN无法被填充
df.bfill() 向后填充:使用下一个有效值,尾部NaN无法被填充
import pandas as pd
file = r'D:\PROJECT\itheima_day9\数据清洗.csv'
df = pd.read_csv(file)
print(df)
df.info()
#各字段缺失值个数
print(df.isnull(),'\n',df.isnull().sum())
#各字段缺失值占比
print(df.isnull().sum()/len(df))
print('='*20)
#删除缺失值
df.drop(labels='t2',axis=1,inplace=True)
print(df)
#删除指定的labels列(axis=1),设置inplace=True 更新原dataframe 否则不影响原数据
print('='*20)
#删除缺失值所在行
print(df.dropna(how='any')) #如果该行有NaN则删除 这里也可以选用inplace选项
print('='*20)
print(df.dropna(how='all'))#如果该行全为NaN 删除该行
print('='*20)
print(df.dropna(subset=['t1'])) #如果指定列中带有NaN 删除该行 subset=['']用于指定列
print('='*20)
#填充缺失值
print(df.fillna(value=df.mean()))#使用.mean()作为value执行fillna操作 不指定列名的情况下用每一列的均值填补各自的缺失值
print('='*20)
print(df.ffill()) #front_fill向前填充 使用该列的上一个有效值进行填充
print('='*20)
print(df.bfill()) #back_fill向后填充 使用该列的下一个有效值进行填充 末尾NaN无法填充
matplotlib具体使用:
matplotlib作为面向python的并且最贴近matlab的可视化库,基本允许我们在python中实现在matlab中相同的作图需求;
这里以折线图和散点图作图为例,简单讲解一下如何使用matplotlib
首先是折线图绘图:
主要的几个方法:
plt.figure():用于设置窗口画布的属性,这里用figsize来调整窗口大小
plt.plot():绘制折线图,*args参数传入x轴数据、y轴数据,支持定义折线颜色
plt.title()、plt.xlabel()、plt.ylabel():设置标题和横纵标签
plt.grid():显示网格
plt.xticks(month) :选中x轴标签 一般于xlabel保持一致 不设置xtick的话可能不会显示全部标签
太密集的标签会被跳过
plt.show():显示绘图
主要流程:plt.plot() -> plt.show() (核心步骤:传数据,显示绘图)
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib
matplotlib.use(('TkAgg'))
#以下设置用于保证title和label中的中文能够正常显示 非必须
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
np.random.seed(25)
month = np.array(range(12)) #使用numpy构造作图需要的数据 x/y轴数据量要相同
sales = np.random.randint(low=80,high=500,size=12)
df = pd.DataFrame({'months':month,'sales':sales}) #dataframe对象用于传入plt
print(df)
#设置窗口大小
plt.figure(figsize=(8,5))
plt.plot(df['months'],df['sales'],color='red')
#设置标题和横纵标签
plt.title('title1')
plt.xlabel('months')
plt.ylabel('sales')
plt.grid() #显示网格
plt.xticks(month) #选中x轴标签 一般于xlabel保持一致 不设置xtick的话可能不会显示全部标签
#太密集的标签会被跳过
plt.show() #显示
接下来是散点图的绘制:
和折线图不同的是,散点绘图使用plt.scatter()而非plt.plot();
这里由于构造数据的性质,不使用.xtick(),否则可能导致局部过于密集
其他操作与折线图绘图操作基本一致
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib
matplotlib.use(('TkAgg'))
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
np.random.seed(25)
x = np.random.randn(50) #正态分布样本 50个
y = 2*x + np.random.randn(50)*0.5
print(x,y)
plt.figure(figsize=(8,5))
plt.scatter(x,y,color='blue') #.scatter()绘制散点图
plt.title('title')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
#plt.xticks(x) 此处不建议使用,x序列并不等差排序,并且可能在某一处非常密集,影响观感
#plt会自动设置xlabel的间隔
plt.show()
tips:在pandas中有内置的plot绘图模块,支持直接调用、直接.show();如下:
import pandas as pd
import matplotlib.pyplot as plt
# DataFrame 直接调用 .plot()
df = pd.DataFrame({
'A': [1, 2, 3, 4],
'B': [4, 3, 2, 1]
})
df.plot(kind='line') # 或 'bar', 'scatter', 'hist' 等
plt.show()
当然Series也支持.plot()绘图;直觉上很奇怪因为他是一维的数据机构;但实际上Series可以使用他的index索引作为x轴数据,values作为y轴数据,如下:
import pandas as pd
import matplotlib.pyplot as plt
# 月度销售额数据
sales = pd.Series([120, 135, 148, 162, 155, 178],
index=['1月', '2月', '3月', '4月', '5月', '6月'])
#不设置index的话 默认是一个从0开始的自增序列
sales.plot(kind='bar', title='上半年销售额', color='steelblue')
plt.ylabel('万元')
plt.show()
最后是一个案例:
数据样式:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib
matplotlib.use('TkAgg') # 新版matplotlib需要指定图形后端处理器
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
np.random.seed(25)
path = r'D:\PROJECT\itheima_day9\数据分析资料\1960-2019全球GDP数据.csv'
df = pd.read_csv(path,encoding='gbk')
#查看NaN情况
print(df.isnull())
df.dropna(how='all',inplace=True)
print(df.keys())
#通过'country'字段分别获取各个国家的GDP信息
china = df[df['country']=='中国']
america = df[df['country']=='美国']
japan = df[df['country']=='日本']
#将索引替换为year 丢掉原来的id(分组后的id已经不连续了) 后续需要使用year作为xlabel
china.set_index('year',inplace=True)
america.set_index('year',inplace=True)
japan.set_index('year',inplace=True)
# china.plot(kind='line')
# plt.show()
plt.title('GDP Info')
#*args:传入x轴和y轴的数据
#这里的label参数用于后续在legend()图例面板中展示对应折线的标签
plt.plot(china.index,china['GDP'],label='china',color='red')
plt.plot(america.index,america['GDP'],label='america',color='blue')
plt.plot(japan.index,japan['GDP'],label='japan',color='green')
plt.grid()
plt.legend()
plt.show()
#print(china)


7万+

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



