Python常用三方库

一、NumPy 

NumPy:Numerical Python,第三方数值计算库,底层C实现,提供ndarray多维数组,是pandas、matplotlib底层基础。

导入约定:

import numpy as np

1. 核心对象:ndarray N维数组

ndarray:n‑dimensional array,多维同类型数组。

和Python原生list关键区别

listnp.ndarray
可以存放不同类型元素全部元素必须相同数据类型
内存分散,链表式存储连续一块内存存储,计算速度快
循环Python层面,慢向量化运算,C底层,速度快
动态变长创建时维度固定
lst = [1,2,3,4]
arr = np.array([1,2,3,4])
print(type(arr)) # numpy.ndarray

ndarray重要属性

arr = np.array([[1,2,3],[4,5,6]])
print(arr.ndim)      # 维度,2
print(arr.shape)     # 形状 (行,列) → (2,3)
print(arr.size)      # 总元素个数 6
print(arr.dtype)     # 元素数据类型 int64
print(arr.itemsize)  # 单个元素字节大小

- shape 是元组:一维(N,),二维(rows,cols),三维(z,y,x)。一维数组shape是(4,),不是(4,1);一维不是列向量也不是行向量。

2. 创建数组常用方法

# 1.从list转换
a1 = np.array([1,2,3])
a2 = np.array([[1,2],[3,4]])

# 指定dtype
a = np.array([1,2], dtype=np.float32)

# 2.全0、全1
np.zeros((2,3))   # 2行3列全0
np.ones((3,2))    # 3行2列全1

# 3.指定值填充
np.full((2,2), 10)

# 4.单位矩阵
np.eye(3)

# 5.等差序列 arange (类似range,支持浮点数)
np.arange(0,10,2) # [0 2 4 6 8]

# 6.等分linspace:在start‑end之间取N个点,包含首尾
np.linspace(0, 10, 5) # [ 0.   2.5  5.   7.5 10. ]

# 7.随机数组
np.random.rand(2,3)      # [0,1)均匀分布
np.random.randn(3,3)     # 标准正态分布
np.random.randint(0,10, size=(2,2)) # 整数随机

数据类型 dtype,常用:int8/int16/int32/int64;float32/float64;bool

arr = np.array([1,2], dtype=np.float64)
arr2 = arr.astype(np.int32) # 类型转换,返回新数组,不修改原数组

坑:astype()不会原地修改,必须接收返回值。

3.索引与切片

(1)索引与切片

一维

arr = np.array([0,1,2,3,4])
print(arr[2])
print(arr[1:4])

二维

arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
arr2d[0,1]   # 第0行第1列,等价 arr2d[0][1],推荐逗号写法
arr2d[1:3, :] # 行切片1‑2,所有列
arr2d[:, 0]   # 所有行,第0列

和list最大坑:numpy切片返回视图view,不是拷贝!共享内存,修改会影响原数组。

a = np.array([1,2,3,4])
b = a[1:3]
b[0] = 99
print(a) # [ 1 99  3  4] 原数组被改动!

list切片是拷贝;numpy切片默认是视图view,共用同一块内存,只为性能。

想要独立拷贝:显式调用 .copy()

b = a[1:3].copy()
b[0]=99
# a不受影响

布尔索引、花式索引:返回 拷贝(新数组,独立内存),修改结果不会影响原数组。

(2)布尔索引

arr[布尔掩码数组]
# 二维:可以分别给行、列传布尔数组
arr[行布尔掩码, 列布尔掩码]

用布尔数组当掩码,取出条件为True对应的元素。

arr = np.array([10, 20, 30, 40, 50])
mask = arr > 25   # 得到布尔掩码数组
print(mask)       # [False False  True  True  True]

res = arr[mask]
print(res)        # [30 40 50]

多条件组合:不能用and / or / not,要用运算符 & | ~,每个条件必须加括号

# 大于20 并且 小于50
res = arr[(arr > 20) & (arr < 50)]
print(res) # [30 40]

# 取反 ~
res = arr[~(arr>25)]
print(res) # [10 20]

二维数组布尔索引

arr2d = np.array([[1,2,3],
                  [4,5,6],
                  [7,8,9]])

mask = arr2d > 4
res = arr2d[mask]
print(res) # [5 6 7 8 9]
# 布尔索引取出结果永远是一维数组!

(3)花式索引

传入整数数组 / 整数列表作为索引,按指定下标取出元素。

一维花式索引

arr[整数序列]
arr = np.array([10,20,30,40,50])

# 传入下标列表
res = arr[[0, 2, 4]]
print(res) # [10 30 50]

# 顺序可以乱序、可以重复取
res = arr[[4,1,1]]
print(res) # [50 20 20]

二维花式索引

两种写法:

arr[行下标数组, 列下标数组]:一一配对取点

arr2d = np.array([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]])

# 取 (0,1) 和 (2,0) 两个点
res = arr2d[[0, 2], [1, 0]]
print(res) # [2 7]

两边整数数组长度最好相等;如果不等,会触发广播机制

一边花式索引,另一边切片 arr[整数序列, :] / arr[:, 整数序列]

选取若干整行:传入行列表

# 取第0行、第2行
res = arr2d[[0,2], :]
print(res)
'''
[[1 2 3]
 [7 8 9]]
'''

选取若干整列

res = arr2d[:, [0,2]]
print(res)
'''
[[1 3]
 [4 6]
 [7 9]]
'''

4. 向量化运算

不写 Python for 循环,直接对整个 ndarray 数组做运算符 / 函数运算;运算在底层 C 实现,避开 Python 循环的开销。

Python 原生 for 循环:每一次迭代都在 Python 虚拟机执行,循环量大很慢。

NumPy 向量化:循环下移到 C 层,数组内存连续,CPU 可以批量处理,速度提升几十~上百倍。

核心思想:把操作施加到数组每一个元素,不用手动遍历。

import numpy as np

arr = np.array([1,2,3,4])

# 向量化,没有for循环
res = arr * 2
print(res) # [2 4 6 8]

(1)运算符向量化(逐元素 element‑wise)

+ - * / // % ** > < >= <= == & | 全部逐元素运算。

*:逐元素相乘,不是矩阵乘法。矩阵乘法用 @ / np.dot()。

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)
print(a // b)
print(a ** 2)  # 每个元素平方 [1 4 9]
print(a > 2)   # [False False  True] 返回布尔数组
print(a == 2)  # [False  True False]

二维同样逐元素:
m1 = np.array([[1,2],[3,4]])
m2 = np.array([[10,20],[30,40]])
print(m1 + m2)
print(m1 * m2) # 逐元素,不是矩阵乘法

(2)广播机制:不同shape数组可以运算,numpy自动扩展维度,不复制数据。

规则:
1. 从尾部维度对齐
2. 维度相等,或者其中一个为1,可以广播
3. 否则报错

一维数组 + 标量

arr = np.array([1,2,3])
arr + 10

二维 (2,3) + 一维 (3,)

m = np.ones((2,3))
v = np.array([10,20,30])
print(m + v)
[[11. 21. 31.]
 [11. 21. 31.]]

(2,1) + (1,3),广播结果 (2,3)

a = np.array([[1],[2]]) # shape(2,1)
b = np.array([[10,20,30]]) # shape(1,3)
print(a + b)
[[11 21 31]
 [12 22 32]]

广播报错例子:(2,3) 和 (2,4),尾部维度 3 vs4,都不为 1,无法广播。

(3)矩阵乘法

写法运算类型说明维度规则
A * BHadamard 积(逐元素相乘)对应位置元素相乘,不是数学矩阵乘法支持广播,可以维度不同,只要可广播
A @ B矩阵乘法(推荐)等价np.matmul,实现标准数学矩阵乘法A(m,k)@B(k,n)
np.matmul(A,B)矩阵乘法@完全等价同上
np.dot(A,B)点积二维数组等价矩阵乘法;一维做向量内积;高维行为特殊,不推荐多维矩阵使用一维向量长度相同;二维满足矩阵乘法规则

@ / np.matmul() 标准矩阵乘法

import numpy as np
A = np.array([[1,2],[3,4]])
B = np.array([[5,6],[7,8]])

print("==== A * B 逐元素 ====")
print(A * B)
'''
[[ 5 12]
 [21 32]]
'''

print("==== A @ B 矩阵乘法 ====")
print(A @ B)
'''
[[19 22]
 [43 50]]
'''

np.dot() 的坑

二维数组:np.dot(A,B)等价A@B

一维数组:np.dot(v1,v2)向量内积(标量)

v1 = np.array([1,2])
v2 = np.array([3,4])
print(np.dot(v1,v2)) # 1*3 +2*4 =11,输出标量

大于 2 维数组:np.dot 和 @行为不一致,工程中禁止用 dot 做多维矩阵运算。

一维数组参与矩阵乘法特殊行为

import numpy as np
M = np.array([[1,2],[3,4]]) # (2,2)
v = np.array([10,20])      # (2,) 一维数组
v_col = v.reshape(-1,1)    # (2,1) 二维列向量

res1 = M @ v
res2 = M @ v_col

print("res1 =", res1)
print("res1.shape =", res1.shape)

print("res2 =")
print(res2)
print("res2.shape =", res2.shape)

res1 = [ 50 110 ]
res1.shape = (2,)

res2 =
[[ 50]
 [110]]
res2.shape = (2, 1)

(4)数组形状操作 reshape /ravel/flatten

arr = [0 1 2 3 4 5]

1. reshape() 修改形状

数组.reshape(dim0, dim1, dim2...)

reshape前后总元素必须完全相等,否则报错。

优先返回视图(共享内存),不复制数据,但不保证一定是视图;

-1:交给numpy自动计算该维度的大小。

reshape(2,3)

arr2 = arr.reshape(2,3)
print(arr2)
'''
[[0 1 2]
 [3 4 5]]
'''
print(arr2.shape) # (2, 3)

6个元素 = 2行 ×3列。

reshape(-1,2),固定列数=2,-1自动计算行数

arr3 = arr.reshape(-1,2)
print(arr3)
'''
[[0 1]
 [2 3]
 [4 5]]
'''
print(arr3.shape) # (3, 2)

 - reshape(-1, 1) → 列向量 (N,1)
- reshape(1, -1) → 行向量 (1,N)

reshape是视图不绝对:如果内存布局不连续,reshape会返回拷贝,修改新数组不一定影响原数组。

2. ravel() 展平为一维

将多维数组拉平成一维;优先返回视图,内存不允许时才做拷贝。

arr2d = np.array([[1,2],[3,4]])
r = arr2d.ravel()
print(r)         # [1 2 3 4]
print(r.shape)   # (4,)

# ravel是视图,修改会影响原数组
r[0] = 999
print(arr2d)
'''
[[999   2]
 [  3   4]]
'''

np.ravel(arr2d) 和 arr2d.ravel()效果一样。

3. flatten() 展平,永远返回拷贝

不管什么情况,一定复制一份全新数据,和原数组完全隔离。

arr2d = np.array([[1,2],[3,4]])
f = arr2d.flatten()
print(f) # [1 2 3 4]

f[0] = 999
print(arr2d)
'''
[[1 2]
 [3 4]]
'''

3. .T 转置
交换数组的各个维度顺序,二维就是行↔列互换。

m = np.arange(6).reshape(2,3)
print(m)
'''
[[0 1 2]
 [3 4 5]]
'''
print(m.shape) # (2, 3)

mt = m.T
print(mt)
'''
[[0 3]
 [1 4]
 [2 5]]
'''
print(mt.shape) # (3, 2)

二维矩阵转置常用.T;高维数组推荐np.transpose()。

5. np.newaxis 增加维度(广播高频)

作用:,不改变数据,等价reshape。

v = np.array([10,20])
print(v)           # [10 20]
print(v.shape)     # (2,)

v[:, np.newaxis]:增加列维度|(N,1)|构造列向量,用于广播

- : 代表保留原来的0轴(2个元素)

- np.newaxis 在后面插入新维度

v_col = v[:, np.newaxis]
print(v_col)
'''
[[10]
 [20]]
'''
print(v_col.shape) # (2, 1)

等价写法:v.reshape(-1,1)

v[np.newaxis, :]:增加行维度|(1,N)|构造行向量

- 在最前面插入长度为1的维度

- : 保留原来全部元素

v_row = v[np.newaxis, :]
print(v_row)
# [[10 20]]
print(v_row.shape) # (1, 2)

等价写法:v.reshape(1,-1)

为什么要用newaxis?之前广播例子:(2,1)+(1,3),一维(2,)无法直接参与该广播,通过np.newaxis增加维度,造出(2,1)列向量,开启广播机制。

(5)np.arange

np.arange(start, stop, step, dtype=None)
start:起始值,默认0,包含该值
stop:终止值,不包含(左闭右开 [start, stop))
step:步长,默认1,可以正数、负数、浮点数
dtype:指定数据类型,不写自动推断

只给 stop,start 默认 0,step 默认 1

import numpy as np
arr = np.arange(10)
print(arr)
# [0 1 2 3 4 5 6 7 8 9]
# 0~9,取不到10

start, stop

arr = np.arange(2,10)
print(arr)
# [2 3 4 5 6 7 8 9]

start, stop, step 步长

arr = np.arange(2,10,2)
print(arr)
# [2 4 6 8]

负步长,倒序

arr = np.arange(5,0,-1)
print(arr)
# [5 4 3 2 1]

浮点数步长

arr = np.arange(0, 1, 0.2)
print(arr)
# [0.  0.2 0.4 0.6 0.8]

配合 reshape,生成多维数组,arange永远输出一维,再 reshape 改变形状

arr = np.arange(6).reshape(2,3)
print(arr)
'''
[[0 1 2]
 [3 4 5]]
'''
rangenp.arange
返回range 迭代器ndarray 数组
支持浮点数不支持支持
可以直接做向量化运算不支持支持

易错坑
1. reshape总元素数量必须一致,否则抛异常;
2. ravel是视图,修改会改动原始数组;flatten拷贝不会;
3. (2,)一维数组,和`(2,1)`列向量打印数字相似,但shape不同,广播、矩阵乘法行为不一样;
4. -1只能在reshape中出现最多一次,不能写reshape(-1,-1),numpy无法推算两个未知数。

5.NumPy 通用函数 ufunc

ufunc:专门做向量化的函数,输入数组,逐元素计算,输出新数组。替代 Python 内置 math 函数,math 只支持单个数字;np 的 ufunc 支持数组。

数学类 ufunc

np.sin(arr)
np.cos(arr)
np.exp(arr)    # e^x
np.log(arr)    # 自然对数 ln
np.log10(arr)
np.sqrt(arr)   # 开平方
np.abs(arr)    # 绝对值
np.square(arr) # 平方

示例对比

import math
# math.sin 只能传单个数字
# math.sin(np.array([1,2,3])) 报错

arr = np.array([0, np.pi/2, np.pi])
res = np.sin(arr) # ufunc向量化,直接算全部元素
print(res)

条件 ufunc:np.where

np.where(condition, x, y)
逻辑:条件为 True 取 x,False 取 y,逐元素。
arr = np.array([1, -2, 3, -4])
res = np.where(arr>0, arr, 0)
print(res) # [1 0 3 0]
也可以只传条件:返回满足条件的下标元组,经常配合布尔索引。

常用统计函数

全部默认对整个数组计算,可以指定`axis`轴。
- axis=0:沿着行方向压缩,按列计算
- axis=1:沿着列方向压缩,按行计算`

arr = np.array([[1,2],[3,4]])
arr.sum()
arr.sum(axis=0) # 列求和
arr.sum(axis=1) # 行求和

arr.mean()
arr.max()
arr.min()
arr.argmax() #最大值下标

np.random

import numpy as np

(1)随机种子 seed

作用:固定随机数序列,保证每次运行代码得到完全一样的随机结果,用于复现实验。

np.random.seed(42)   # 传入任意整数作为种子

关键点:seed()只需要设置一次;不是每生成一次随机数都调用。

不设置 seed,每次运行随机结果不一样。

(2)生成均匀分布随机数

np.random.rand(d0,d1,d2...)

生成 [0,1) 区间均匀分布浮点数,参数直接传各个维度大小。

# shape(2,3),0~1之间
arr = np.random.rand(2,3)
print(arr.shape) # (2, 3)

np.random.uniform(low, high, size),指定区间的均匀分布,[low, high)

# 生成5个数字,范围 [1,10)
arr = np.random.uniform(low=1, high=10, size=5)
# 2行2列
arr2 = np.random.uniform(0,100,size=(2,2))

(3)正态(高斯)分布

标准正态分布:均值 0,方差 1 N(0,1)

np.random.randn(d0,d1...)
arr = np.random.randn(2,3)

自定义正态分布
loc:均值 μ
scale:标准差 σ

np.random.normal(loc, scale, size)
# 均值=10,标准差=2,shape(3,)
arr = np.random.normal(loc=10, scale=2, size=3)

(4)随机整数

np.random.randint(low, high=None, size)

生成整数,区间 [low, high),左闭右开

# high不写:区间 [0, low)
arr1 = np.random.randint(0,10,size=5) # [0,10) 5个整数

# 二维
arr2 = np.random.randint(1,100,size=(2,3))

(5)随机抽样、打乱

从给定序列中随机采样

np.random.choice(a, size, replace=True, p=None)
a:数据源(整数 / 数组)
size:输出形状
replace=True:有放回抽样;False无放回,不能抽比样本总数更多的数
p:每个元素被抽取的概率,和 a 长度相同
# 从[10,20,30,40]中抽3个,有放回
res1 = np.random.choice([10,20,30,40], size=3)

# 无放回抽样
res2 = np.random.choice([10,20,30,40], size=3, replace=False)

# 指定概率:10取到概率0.8,20为0.2
res3 = np.random.choice([10,20], size=5, p=[0.8,0.2])

np.random.shuffle(arr):原地打乱数组顺序,无返回值,只打乱第一维。

arr = np.array([1,2,3,4,5])
np.random.shuffle(arr)
print(arr) #原数组被打乱

np.random.permutation(arr):返回打乱后的新拷贝,不修改原数组。

arr = np.array([1,2,3,4,5])
res = np.random.permutation(arr)
print(arr) #原数组不变

shuffle 原地修改;permutation 返回新数组。

6.拼接与分割

核心函数:底层主函数 np.concatenate;vstack/hstack 是便捷封装;分割:np.split / np.vsplit / np.hsplit / np.array_split

import numpy as np

a = np.array([[1, 2],
              [3, 4]])
b = np.array([[5, 6]])   # shape (1,2)
c = np.array([[7],
              [8]])      # shape (2,1)

(1)np.concatenate

np.concatenate( (数组1,数组2,...), axis=0 )

axis=0:竖直方向拼接,增加行,要求除 0 轴以外其余维度完全匹配
axis=1:水平方向拼接,增加列,要求除 1 轴以外其余维度完全匹配

# axis=0 竖直拼接,增加行
res0 = np.concatenate((a, b), axis=0)
print(res0)
'''
[[1 2]
 [3 4]
 [5 6]]
'''

# axis=1 水平拼接,增加列
res1 = np.concatenate((a, c), axis=1)
print(res1)
'''
[[1 2 7]
 [3 4 8]]
'''

拼接时,非拼接维度的 shape 必须完全一致,否则报错。例:a(2,2) 和 b(1,3),axis=0拼接,第二维 2≠3,直接报错。

(2)np.vstack () 竖直堆叠

v → vertical 竖直,增加行

res = np.vstack([a, b])
# 等价 np.concatenate((a,b), axis=0)

np.hstack () 水平堆叠
h → horizontal 水平,增加列

res = np.hstack([a, c])
# 等价 np.concatenate((a,c), axis=1)

小区别:
concatenate 必须指定 axis;
vstack/hstack 自动固定 axis,可读性更好,内部调用 concatenate。

(3)分割

np.split

np.split(arr, 分割份数 / 分割位置列表, axis=0)
axis=0:按行切(竖直分割)
axis=1:按列切(水平分割)

np.split必须等分,总长度必须能被份数整除,否则抛异常。

arr = np.arange(12).reshape(3,4)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
'''
# axis=0,沿行切成3份
parts = np.split(arr, 3, axis=0)
print(parts[0]) # [[0 1 2 3]]

# 按指定位置切,第二个参数传列表
parts2 = np.split(arr, [1], axis=1)
# 在索引1位置切开,分成 [:1] 和 [1:]

np.vsplit/np.hsplit 快捷分割

np.vsplit(arr, n):等价 np.split(arr, n, axis=0),按行切

np.hsplit(arr, n):等价 np.split(arr, n, axis=1),按列切

# 按行切3份
p1 = np.vsplit(arr, 3)
# 按列切2份
p2 = np.hsplit(arr, 2)

np.array_split

np.split要求严格等分;np.array_split可以不等分,不会报错。当维度长度不能整除分割份数时,部分子数组会多一个元素。

arr = np.arange(5)
res = np.array_split(arr, 2)
print(res) # [array([0,1,2]), array([3,4])]
函数作用axis特点
np.concatenate((a,b),axis=0)拼接,增加行0底层函数,非拼接维度 shape 必须匹配
np.concatenate((a,b),axis=1)拼接,增加列1底层函数
np.vstack([a,b])竖直堆叠,增加行固定 0concatenate 封装
np.hstack([a,b])水平堆叠,增加列固定 1concatenate 封装
np.split(arr,N,axis=0)分割数组0/1必须等分,否则报错
np.vsplit按行分割固定 0split 封装
np.hsplit按列分割固定 1split 封装
np.array_split分割数组0/1支持不等分

二、Pandas

Pandas 基于 NumPy,两大核心:Series 一维带索引序列、DataFrame 二维表格(Excel 表结构)

1. Series 一维序列

结构:索引index + 值values;可以自定义标签索引,不只是 0,1,2 数字。

(1)创建 Series

列表创建,默认数字索引0,1,2,3

s1 = pd.Series([10,20,30,40])
print("s1:\n",s1)
'''
0    10
1    20
2    30
3    40
dtype: int64
'''

指定自定义索引

s2 = pd.Series([10,20,30,40], index=["a","b","c","d"])
print("\ns2:\n",s2)
'''
a    10
b    20
c    30
d    40
dtype: int64
'''

字典创建,字典key直接成为index

dic = {"a":100, "b":200, "c":300}
s3 = pd.Series(dic)
print("\ns3:\n",s3)
'''
a    100
b    200
c    300
dtype: int64
'''

(2)Series 属性

print(s2.index)      #索引对象 Index(['a', 'b', 'c', 'd'], dtype='object')
print(s2.values)     #取出数值,返回numpy数组 [10 20 30 40]
print(s2.dtype)      #数据类型 int64
print(s2.shape)      #形状 (4,)

(3)Series 取值

print(s2["a"]) #标签索引取值 10
print(s2[0])   #位置索引取值 10
#切片:标签切片闭区间,首尾都取
print(s2["a":"c"])
'''
a    10
b    20
c    30
dtype: int64
'''

(4)Series 运算

支持向量化运算,和 numpy 类似,不需要循环

print(s2 * 2)
'''
a    20
b    40
c    60
d    80
dtype: int64
'''

2. DataFrame 二维表格

类比 Excel 表格:行 index,列 columns;DataFrame 的每一列,就是一个 Series。

(1)创建 DataFrame

#方式1:字典创建,字典key作为列名
data = {
    "name":["张三","李四","王五"],
    "age":[18,20,22],
    "score":[88,92,79]
}
df = pd.DataFrame(data)
print("df:\n",df)
'''
  name  age  score
0   张三   18     88
1   李四   20     92
2   王五   22     79
'''

#方式2:numpy二维数组创建,手动指定列名、行索引
arr = np.array([[18,88],[20,92],[22,79]])
df2 = pd.DataFrame(arr, columns=["age","score"], index=[10,20,30])
print("\ndf2:\n",df2)
'''
    age  score
10   18     88
20   20     92
30   22     79
'''

(2)DataFrame 常用属性与查看数据

print(df.index)      #行索引 RangeIndex(start=0, stop=3, step=1)
print(df.columns)    #列索引 Index(['name', 'age', 'score'], dtype='object')
print(df.values)     #转为numpy二维数组
print(df.shape)      #(3, 3)  (行数,列数)
print(df.dtypes)     #每一列的数据类型

print(df.head(2))    #查看前2行;不传参数默认前5行
print(df.tail(1))    #查看最后1行

print(df.info())     #表格概览:行数、列名、非空值数量、数据类型
'''
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3 entries, 0 to 2
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   name    3 non-null      object
 1   age     3 non-null      int64 
 2   score   3 non-null      int64 
dtypes: int64(2), object(1)
memory usage: 200.0+ bytes
'''

print(df.describe()) #只对数值列做统计:count mean std min max四分位数
'''
             age      score
count   3.000000   3.000000
mean   20.000000  86.333333
std     2.000000   6.506407
min    18.000000  79.000000
25%    19.000000  83.500000
50%    20.000000  88.000000
75%    21.000000  90.000000
max    22.000000  92.000000
'''

3. 索引选取数据

(1)取列

#取单列,返回Series
col_series = df["name"]
print(col_series)
'''
0    张三
1    李四
2    王五
Name: name, dtype: object
'''

#取多列,传入列表,返回DataFrame
col_df = df[["name","age"]]
print(col_df)
'''
  name  age
0   张三   18
1   李四   20
2   王五   22
'''

坑:df[]直接写,只能取列,不能直接写数字取行;取行用loc、iloc。

(2)loc:按标签索引(行标签、列标签)

df.loc[行标签, 列标签],按标签(index 名字)取值,闭区间,两边都包含 [start, end]

#取单行,行标签0
print(df.loc[0])
'''
name     张三
age      18
score    88
Name: 0, dtype: object
'''

#取多行
print(df.loc[[0,2]])
'''
  name  age  score
0   张三   18     88
2   王五   22     79
'''

#行+列同时指定
print(df.loc[0, "name"]) #张三

#切片,loc[0:2],标签0、1、2全部取出,两边都包含
print(df.loc[0:2, ["name","age"]])
'''
  name  age
0   张三   18
1   李四   20
2   王五   22
'''

(3)iloc

语法:df.iloc[行位置, 列位置],按数字位置(0 开始的下标)取值,左闭右开 [start, end)

print(df.iloc[0])          #第0行
print(df.iloc[0:2, 0:2])   #行0,1;列0,1,左闭右开
'''
  name  age
0   张三   18
1   李四   20
'''

(4)布尔索引

#条件,返回布尔掩码
mask = df["age"] >19
print(mask)
'''
0    False
1     True
2     True
Name: age, dtype: bool
'''

#掩码筛选,保留True对应的行
res = df[mask]
print(res)
'''
  name  age  score
1   李四   20     92
2   王五   22     79
'''

#多条件:&代表且,|代表或;每个条件必须加括号!
res2 = df[ (df["age"]>18) & (df["score"]>80) ]
print(res2)
'''
  name  age  score
1   李四   20     92
'''

(5)列操作:新增、修改、删除

#新增一列
df["gender"] = ["男","男","女"]
print(df)
'''
  name  age  score gender
0   张三   18     88     男
1   李四   20     92     男
2   王五   22     79     女
'''

#修改整列
df["age"] = df["age"] + 1
print(df["age"])
# 0    19
# 1    21
# 2    23

#删除列
# axis=1代表列;inplace=True原地修改原df,不生成新对象
df.drop("gender", axis=1, inplace=True)
print(df.columns) #Index(['name', 'age', 'score'], dtype='object')

(5)文件读写

#读写csv文件
df.to_csv("test.csv", index=False) #index=False:不把行索引写入文件
df_read = pd.read_csv("test.csv")
print(df_read)

#读写excel(需要pip install openpyxl)
df.to_excel("test.xlsx", index=False)
df_read_excel = pd.read_excel("test.xlsx")

(6)缺失值处理

#构造带缺失的DataFrame
df_miss = pd.DataFrame({
    "a":[1,np.nan,3],
    "b":[np.nan,5,6]
})
print(df_miss)
'''
     a    b
0  1.0  NaN
1  NaN  5.0
2  3.0  6.0
'''

print(df_miss.isna())       #判断每个位置是否缺失,返回布尔表格
print(df_miss.isna().sum()) #统计每一列缺失值的数量

df_drop = df_miss.dropna() #删除存在缺失的行,返回新df
print(df_drop)

df_fill = df_miss.fillna(0) #缺失值填充为0,返回新df
print(df_fill)
'''
     a    b
0  1.0  0.0
1  0.0  5.0
2  3.0  6.0
'''

(7)统计运算

print(df["age"].sum())      #求和
print(df["age"].mean())     #平均值
print(df["age"].max())      #最大值
print(df["age"].min())      #最小值
print(df["score"].value_counts()) #统计该列每个值出现次数

4.排序聚合

(1) sort_values:按值排序

df.sort_values(by="列名", ascending=True, inplace=False)
by:指定按哪一列 / 多列排序
ascending=True:升序从小到大;False降序从大到小
inplace=False:默认返回新 DataFrame,不修改原数据;True原地修改
# 按score分数升序
df1 = df.sort_values(by="score")
print("按score升序:\n",df1)
'''
  name class  age  score
2   王五    2班   19     79
3   赵六    2班   22     85
0   张三    1班   18     88
4   钱七    1班   21     90
1   李四    1班   20     92
'''

# 多列排序:先按班级,班级相同再按分数降序
df3 = df.sort_values(by=["class","score"], ascending=[True,False])
print("\n多列排序:\n",df3)
'''
  name class  age  score
1   李四    1班   20     92
4   钱七    1班   21     90
0   张三    1班   18     88
3   赵六    2班   22     85
2   王五    2班   19     79
'''

(2)sort_index:按行索引排序

# 先打乱顺序
df_shuffle = df.sample(frac=1, random_state=42)
print("打乱后的df:\n",df_shuffle)

# 恢复索引顺序
df_sort_idx = df_shuffle.sort_index()
print("\nsort_index恢复索引:\n",df_sort_idx)

(3)groupby 分组聚合

groupby 逻辑:拆分 → 应用函数 → 合并结果 按某一列相同的值分组,然后对每组做统计计算。

基础用法

# 按照class班级分组
group_obj = df.groupby("class")
print(group_obj)
# <pandas.core.groupby.generic.DataFrameGroupBy object at 0x......>
# groupby返回分组对象,直接print看不到数据,需要调用聚合函数

常用聚合函数

# 对全部数值列做聚合
res = group_obj.mean()
print("按班级分组求均值:\n",res)
'''
             age      score
class                      
1班    19.666667  90.000000
2班    20.500000  82.000000
'''

# 其它聚合
print("\n求和:\n", group_obj.sum())
print("\n最大值:\n", group_obj.max())
print("\n计数:\n", group_obj.count())

只对指定一列聚合

#分组后,只取score列,计算平均分
res_score = df.groupby("class")["score"].mean()
print("\n各班平均分:\n",res_score)
'''
class
1班    90.0
2班    82.0
Name: score, dtype: float64
'''

agg ():一次执行多个不同聚合操作,可以同时指定多个统计方式

#对score列,同时计算:均值、最大值、最小值
res_agg = df.groupby("class")["score"].agg(["mean","max","min"])
print("\nagg多聚合:\n",res_agg)
'''
            mean  max  min
class                    
1班    90.000000   92   88
2班    82.000000   85   79
'''

agg 给列起自定义名字

res_rename = df.groupby("class").agg(
    平均分=("score","mean"),
    最高分=("score","max"),
    人数=("name","count")
)
print("\n自定义聚合列名:\n",res_rename)
'''
           平均分  最高分  人数
class                    
1班    90.000000   92   3
2班    82.000000   85   2
'''

多列分组:按多个字段分组

先按班级,再按其他字段

# 示例:如果有gender性别列,df.groupby(["class","gender"])

groupby 重置索引 reset_index ()

groupby 之后分组字段会变成行索引;reset_index()把它变回普通列。

res = df.groupby("class")["score"].mean()
print(res)
'''
class
1班    90.0
2班    82.0
'''
res = df.groupby("class")["score"].mean().reset_index()
print("\nreset_index之后:\n",res)
'''
  class  score
0    1班   90.0
1    2班   82.0
'''

高频坑:groupby 结果默认把分组字段作为 index,做后续表格合并时经常需要reset_index()。

5.apply 自定义函数

apply:把自定义函数作用到 Series 的每一个元素,或者 DataFrame 的每一行 / 每一列。
注意:优先用 pandas、numpy 内置向量化运算;循环 / 简单逻辑不要优先 apply,性能不如向量化。

import pandas as pd

df = pd.DataFrame({
    "name":["张三","李四","王五","赵六"],
    "age":[18,20,19,22],
    "score":[88,92,79,85]
})
print(df)
'''
  name  age  score
0   张三   18     88
1   李四   20     92
2   王五   19     79
3   赵六   22     85
'''

(1)Series.apply ():作用于列中每一个元素

简单函数,分数判断等级

def get_level(score):
    if score >=90:
        return "A"
    elif score >=80:
        return "B"
    else:
        return "C"

# 对score列Series使用apply
df["level"] = df["score"].apply(get_level)
print(df)
'''
  name  age  score level
0   张三   18     88     B
1   李四   20     92     A
2   王五   19     79     C
3   赵六   22     85     B
'''

配合 lambda 匿名函数,简短逻辑不用 def

# age +2
df["age_plus2"] = df["age"].apply(lambda x: x+2)
print(df[["age","age_plus2"]])
'''
   age  age_plus2
0   18         20
1   20         22
2   19         21
3   22         24
'''

(2)DataFrame.apply ():作用于行或者列

参数 axis:
axis=0 默认:按列,函数接收每一列 Series
axis=1:按行,函数接收每一行 Series,最常用,可以同时读取多个列的值
axis=1,按行处理,可以同时访问多列

需求:生成描述字符串,张三,18岁,分数88

def gen_desc(row):
    # row代表一行,可以通过列名取各个字段
    return f"{row['name']},{row['age']}岁,分数{row['score']}"

df["desc"] = df.apply(gen_desc, axis=1)
print(df["desc"])
'''
0    张三,18岁,分数88
1    李四,20岁,分数92
2    王五,19岁,分数79
3    赵六,22岁,分数85
Name: desc, dtype: object
'''

axis=1 才是遍历行。

(3)apply 传额外参数

函数除了 row 还需要别的参数,用args传元组。

def add_offset(x, offset):
    return x + offset

df["score_offset"] = df["score"].apply(add_offset, args=(5,))
print(df[["score","score_offset"]])
'''
   score  score_offset
0     88            93
1     92            97
2     79            84
3     85            90
'''

applymap(旧版本 pandas,全表每个元素),新版本 pandas 已经废弃applymap,推荐使用 df.map() / df.apply(lambda x:x.map(func))。

apply 性能,Series.apply:遍历列中每一个元素,本质是循环;简单计算优先用向量化运算。

#优先写这个(向量化,速度快)
df["score"] + 10

#不要优先写这个,速度慢
df["score"].apply(lambda x:x+10)

DataFrame.apply(axis=1)遍历行,性能更差,大数据量尽量少用。

适合 apply 场景:逻辑复杂,多分支判断,很难写成向量化表达式。

map () 补充:Series 映射,map专门用于 Series 值映射,经常做字典映射替换。

s = pd.Series([1,2,3])
#字典映射
s2 = s.map({1:"一",2:"二",3:"三"})
print(s2)
'''
0    一
1    二
2    三
dtype: object
'''
方法对象作用
Series.apply()Series对每个元素执行函数,支持复杂 def 函数
Series.map()Series元素映射,适合字典映射、简单转换
DataFrame.apply(func,axis=1)DataFrame按行,一行作为对象传入函数,可以读取多列

三、Matplotlib

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 解决中文显示,防止中文方框乱码
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False #解决负号显示异常

Matplotlib:Python底层绘图库;pandas、seaborn绘图底层都依赖它。

两套写法:

 - plt.xxx:简单快速,脚本、交互式画图用。内部有隐藏的全局状态:当前画布 figure、当前子图 axes

 - fig, ax = plt.subplots():显式创建画布对象fig和子图对象ax,一切操作都通过对象调用,没有隐藏全局状态。

1. plt.subplots () 

创建画布 Figure 和坐标轴 Axes 对象。

plt.subplots(nrows=1, ncols=1, figsize=(6,4), dpi=100)
nrows:子图行数;ncols:子图列数
figsize=(w,h):画布宽高,单位英寸
dpi:画布分辨率
返回:fig画布对象,ax坐标轴对象;多子图返回数组axes[i,j]
# 1个子图
fig, ax = plt.subplots(figsize=(6,4))
ax.plot([1,2,3], [2,4,1])
fig.tight_layout()
plt.show()

# 2行2列多个子图
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(8,6))
axes[0,0].plot([1,2],[3,1])
axes[1,1].bar(["A","B"],[10,20])
fig.tight_layout()
plt.show()

fig.tight_layout () :自动调整子图间距,解决标题、坐标轴标签重叠。

ig.savefig () 保存画布为图片文件,必须写在 plt.show () 之前,show 会清空画布。

fig.savefig(fname, dpi=150, bbox_inches="tight")
fname:输出文件名,如"out.png"
dpi:输出分辨率
bbox_inches="tight":裁掉多余白边

plt.show () 弹出绘图窗口,渲染图像,执行后内存画布清空。

2.坐标轴设置函数

函数说明
ax.set_title(text)设置子图标题
ax.set_xlabel(text)X 轴名称
ax.set_ylabel(text)Y 轴名称
ax.set_xlim(left,right)X 轴显示范围
ax.set_ylim(bottom,top)Y 轴显示范围
ax.set_xticks(list)X 轴刻度位置
ax.set_xticklabels(list)X 轴刻度文字
ax.legend()显示图例,绘图时需要指定 label
ax.grid(True,alpha=0.3)绘制网格,alpha 透明度 0~1

plt 状态机对应:plt.title()、plt.xlabel()、plt.ylabel()、plt.xlim()、plt.ylim()、plt.legend()、plt.grid()

# 面向对象写法
fig, ax = plt.subplots(figsize=(5, 3))
ax.plot([1, 2, 3], [2, 4, 1], label="样本曲线")
ax.set_title("坐标轴设置示例")
ax.set_xlabel("X轴")
ax.set_ylabel("Y轴")
ax.set_xlim(0, 4)
ax.set_ylim(0, 5)
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()

# plt 状态机写法
plt.plot([1, 2, 3], [2, 4, 1], label="样本曲线")
plt.title("坐标轴设置示例")
plt.xlabel("X轴")
plt.ylabel("Y轴")
plt.xlim(0, 4)
plt.ylim(0, 5)
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

(3)折线图

ax.plot () /plt.plot () 折线图

函数说明:绘制折线,适合趋势、时序数据。

ax.plot(x, y, color="red", marker="o", linestyle="-", 
linewidth=2, markersize=6, label="曲线")

x,y:坐标序列

color:线条颜色;marker点标记;linestyle线条样式

linewidth线宽;markersize标记大小;label图例名称
x = np.arange(1, 6)
y = np.array([2, 4, 1, 5, 3])

# 面向对象
fig, ax = plt.subplots(figsize=(6, 4))
ax.plot(x, y, color='red', marker='o', linestyle='-', label='销量')
ax.set_title('销量折线')
ax.set_xlabel('月份')
ax.set_ylabel('销量')
ax.legend()
ax.grid(alpha=0.3)
plt.show()

# plt 状态机
plt.plot(x, y, color='red', marker='o', linestyle='-', label='销量')
plt.title('销量折线')
plt.xlabel('月份')
plt.ylabel('销量')
plt.legend()
plt.grid(alpha=0.3)
plt.show()

(4)ax.bar () /plt.bar () 垂直柱状图

ax.bar(x, height, width=0.6, color="#3498db", alpha=0.8)

x:类别标签;height柱子高度;width柱子宽度;alpha透明度
cate = ["1班","2班","3班"]
val = [88,82,91]

#面向对象
fig, ax = plt.subplots(figsize=(5,4))
ax.bar(cate, val, color=["#3498db","#2ecc71","#e74c3c"])
ax.set_title("各班平均分")
ax.set_ylabel("分数")
ax.set_ylim(70,95)
plt.show()

#plt状态机
plt.bar(cate, val, color=["#3498db","#2ecc71","#e74c3c"])
plt.title("各班平均分")
plt.ylabel("分数")
plt.ylim(70,95)
plt.show()

(5)ax.barh () /plt.barh () 水平柱状图

ax.barh(y, width, height=0.6)

y 轴类别;width柱子横向长度。
cate = ["1班","2班","3班"]
val = [88,82,91]

fig, ax = plt.subplots(figsize=(5,4))
ax.barh(cate, val)
ax.set_xlabel("分数")
plt.show()

(6)其它

x.scatter () /plt.scatter () 散点图

ax.scatter(x, y, s=50, c="orange", alpha=0.7)
s点大小;c点颜色;alpha透明度。
ax.hist () /plt.hist () 直方图

ax.hist(data, bins=20, alpha=0.7, color="green")

data一维数组;bins分组区间数量。
ax.pie () /plt.pie () 饼图

ax.pie(x, labels=labels, autopct="%.1f%%", startangle=90)

x各类别数值;labels标签;autopct格式化百分比;startangle起始旋转角度。
pandas 内置 .plot ()

pandas 封装 matplotlib,直接对 DataFrame/Series 绘图。

df.plot(kind="line/bar/barh/hist", figsize=(6,4))

df = pd.DataFrame({
    "math":[88,92,79,85],
    "english":[82,85,90,77]
}, index=["张三","李四","王五","赵六"])

df.plot(kind="bar", figsize=(6,4))
plt.title("学生成绩")
plt.show()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值