0%

Python-数据处理科学计算

Python 在数据处理与科学计算相关的实践。如:

  • NumPy:Numerical Python,Python 科学计算基础库。
  • pandas:[‘pændəz],基于 Numpy 开发,提供高性能、高级、易使用的数据结构与各种数据分析工具。
  • SciPy:科学计算包: 解决线性代数、概率论、积分等任务的工具
  • blaze:Python 数据值计算库,号称下一代的 Numpy

概述

  • 基本操作:
    • 数据导入:从文件、数据库、其他数据类型
    • 数据处理:清理、整合、规范化、切片、切块、变形、转换、聚合等
    • 建模:设计算法,构建模型

numpy

NumPy:Numerical Python,Python 科学计算基础库。

  • 高性能处理大型多维数组,包含大量数组快速操作的 API,如数学、逻辑、形状操作、排序、选择、输入输出、离散傅立叶变换、基本线性代数,基本统计运算和随机模拟等等。
  • 特点:
    • 高效:比 Python 基本数据结构要快
    • 资源占用少:矩阵运算
    • 基础:众多其他数据计算库依赖于它
    • 数据类型适用于中间数据类型,如与 OpenCV、PyTorch 的数据类型的接口。
    • 矩阵运算功能
  • 矢量化:代码中没有任何显式的循环、索引等。
  • 广播:各操作的隐式的逐元素行为

基本使用

1
2
3
4
5
6
7
8
9
# 安装
pip install numpy
# 使用
import numpy as np

# 配置
np.random.seed(0)
np.set_printoptions(threshold=sys.maxsize) # 强制打印整个数组
np.set_printoptions(suppress=True, precision=3) # 输出时不采用指数形式,不要指数 e

ndarray 对象

ndarray:相同数据类型的 n 维数组
特点:相比于 list

  • 创建时固定大小,变更大小会删原值创新值
  • 元素数据类型相同
  • 提前编译了其相关操作数据运算等操作,比 list 更快

创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 转换
a=np.array([1,2,3]) #由 list 生成 ndarray
a=np.array(p_object, # 数组或嵌套的数列
dtype=None, # 数组元素的数据类与时共进
copy=True, # 是否需要复制
order='K', # 创建数组的样式,C 为行方向,F 为列方向,A 为任意方向(默认)
subok=False, # 默认返回一个与基类类型一致的数组
ndmin=0) # 生成数组的最小维度
np.array([[1,2],[3,4]],dtype=complex)

# 以一定步长取
b=np.arange(1,60.1)
# 以一定数量取
b=np.linspace(0,2,9) # 0 到 2 的 9 个数


# arange
np.arange(0,2,0.3) # 指定范围,浮点数
np.arange(5) # array([0, 1, 2, 3, 4])


# linspace
np.linspace(0,2,9) #


center=[[-1.50,-60.33],[68.25 ,10.21],[-5.26,88.96],[-82.35,24.80]]
center=np.float32(center)


# 特殊数组
a[[1,3,4]]=0
a[[1,3,4]]+=1
b=np.array([1,2,3])
a[b]

np.fomfunction(f,(5,4),dtype=int)

a= np.array([[1,2],[3,4]])
a = np.mat("0 1 2;1 0 3; 4 -3 8")

# 元素未知,大小已知
np.random.random(3)
np.random.random((2,3))

np.zeros((3,4)) # 全 0
np.zeros(3,int)
np.ones((2,3,4)) # 全 1
np.empty((2,3)) # 全空数组,每个值都接近于 0
np.full(3,7.)

# 随机数
np.random.rand(4,2) # [0,1)之间的数,4 行 2 列
np.random.randn() # 标准正态分布
np.random.randint(0,10,30) # [0-10)之间,随机取30个

# [0,1)之间的浮点数
np.random.random_sample(size=None)
np.random.random(size=None)
np.random.ranf(size=None)
np.random.sample(size=None)
np.random.choice(a_list,size=None,replace=True,p=None) # 从一维数组中生成随机数, a 为一维数组类似数据或整数;size 为数组维度;p 为数组中的数据出现的概率

创建全黑图

1
2
img_black=np.full((img_height,img_width),0)
new_img = np.vstack([img_cv2, img_black])

属性

设 axis=i ,则 numpy 沿着第 i 个下标变化的方向进行操作,

1
2
3
4
5
6
7
8
a=np.array([1,2,3])
type(a) #<class 'numpy.ndarray'>
a.dtype # 元素的数据类型 dtype('int64'),a.dtype.name 'int64'
a.shape # 形状,(3,5)
a.size # 元素个数,15
a.ndim # 维度/轴/的个数, 1,dimensions,维度,axis,軕
a.itemsize # 每个元素的字节大小 float64 的为 8
a.data # a 的内存地址,一般不用,而是用索引来访问数组中的元素
  • a.ndim,即 shape 的长度
    • 维度:dimensions
    • 轴:axis,NumPy 中的轴简单来说就是方向的意思,使用数字 0、1、2 表示,一维数组只有 0 轴,二维数组有 0、1 轴,三维数组有 0、1、2 轴,
    • 秩:rank(轴的个数)

数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
arr1 = np.array([1, 2, 3])
arr1 = np.array([1, 2, 3],dtype=np.float64)

arr2 = np.array([1.111, 2.222, 3.333])
# 当前数据类型
print(arr1.dtype)
# 修改数据类型
arr1 = arr1.astype(np.int64)
print(arr1.dtype)
# 保留一位小数
arr2 = np.round(arr2, 1)
print(arr2)

a=np.intc(3)
类型描述
int_默认的整数类型(类似于 C 语言中的 long,int32 或 int64)
intc与 C 的 int 类型一样,一般是 int32 或 int 64
intp用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64)
int8字节(-128 to 127)
int16整数(-32768 to 32767)
int32整数(-2147483648 to 2147483647)
int64整数(-9223372036854775808 to 9223372036854775807)
uint8无符号整数(0 to 255),构建 RGB 图像常用
uint16无符号整数(0 to 65535)
uint32无符号整数(0 to 4294967295)
uint64无符号整数(0 to 18446744073709551615)
bool_布尔型数据类型(True 或者 False)
float_float64 类型的简写
float16半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
float32单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
float64双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
complex_complex128 类型的简写,即 128 位复数
complex64复数,表示双 32 位浮点数(实数部分和虚数部分)
complex128复数,表示双 64 位浮点数(实数部分和虚数部分)

基本操作

数学运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
np.abs(x)  # 绝对值
np.fabs(x) #
np.sqrt()
np.square() # 平方
np.exp() # 指数
np.log2 # 对数
np.log10
np.log(x,base)
np.sign() # 符号函数(大于 0 的数返回 1、小于 0 的数返回-1、0 返回 0 值)
# 取整
np.ceil() # 向上取整
np.floor() # 向下取整
np.round()
np.rint() # 最近的整数
np.isnan() # 判断是否缺失
np.isfinite() # 判断是否有限
np.isinf(x) # 判断是否无限
np.power(x,y) # 幂运算
np.mod(x,y) # 余数

# 与数字加/减/乘/除/乘方/bool 为每个元素都进行这一操作
a**2
a>0
# 数组间操作
a+b
a-b


import numpy as np

# 相同行数,相同列数,对应相加/减/乘/除
a = np.arange(12).reshape(3, 4)
b = np.arange(20, 32).reshape(3, 4)
a+b
a*b

# 相同行数,或相同列数,广播机制,扩宽
c=np.arrange(10)**3
# 矩阵乘积
a@b
a.dot(b)
np.dot(a,b)

索引切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
a=np.arange(1,6)


# 切片
a[2:5:2]
a[::-1]
a[a>5]
a[a>5]=0 # 将值大于5的置为0
a[(a>=3)&(a<=5)]=0
np.where(a>5)

np.clip(a,3,5) # 即a[a<3]=3;a[a>5]=5
# 索引
arr=np.arange(24).reshape(3,8)

# 索引+切片
arr[2,4] # 某一个值,第三行第四列
b[0:5,1] # 0 到 5 行的行索引为 1 的元素
b[:,1] #所有行的行索引为 1 的元素
b[-1] #最后一行,b[-1,:]
b[...,1] #b[:,:,2],三个点表示产生完整索引元组所需的冒号
b[2,...] #b[2,:,:]

# bool 索引
a=np.arange(12).reshape(3,4)
b=a>4
a[b]

np.nonezero(a) # 返回 a 中非 0 元素的索引

统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 标准差
np.std

# 方差
np.var()

np.max(arr) # 最大值
np.min(arr) # 最小值
np.sum(arr) # 求和

np.max(arr, 1) # 某一轴上的最大值
np.min(arr, 1) # 某一轴上的最小值
np.sum(a,axis=1) # 某一轴上取

np.sort(a)

np.mean(arr) # 平均值
np.mean(arr, axis=1) # 某一行、一列的平均值

np.argmax(arr) # 最大值索引
np.argmax(arr, axis=1)

np.argmin(arr) # 最小值索引
np.argmin(arr, axis=1)


np.any(a>5)
np.any(a>5,axis=1)


np.ptp(arr) # 极差
np.ptp(arr, axis=1)

np.var(arr) # 方差

np.std(arr) # 标准差

np.median(arr) # 中位数
# 累加的值
np.cumsum(a, # 数组
axis=None, # 轴索引
dtype=None, # 数据类型,若不指定,则默认与a一致
out=None) # 用来放置结果的替代输出数组,它必须具有与输出结果具有相同的形状和数据缓冲区长度

np.diff(a) # 累差的值

np.transpose(a) # 转置
np.clip(a,5,9) # 矩阵收缩,大于最大值 9 的的变成 9,小于最小值 5 的变成 5

import numpy as np

arr = np.array([1, 3, 5, 2, 4, 6, 1, 5, 3])
# 去除重复元素
print(np.unique(arr))
# 去重数组的索引数组
u, indices = np.unique(arr, return_index=True)
print(indices)
# 去重元素的重复数量
u, indices = np.unique(arr, return_counts=True)
print(indices)

复制与视图

  • arr.view():视图(浅复制)只是原有数据的一个引用,通过该引用可访问、操作原有数据,如果我们对视图进行修改,它会影响原始数据,因为浅复制共享内存。
  • 切片会返回一个视图,不再需要原始数组时,应在切片后使用 copy
  • arr.copy():副本(深复制)是对数据的完整拷贝,如果我们对副本进行修改,它不会影响到原始数据,因为深复制不共享内存。
1
2
3
4
5
6
7
8
9
10
a=np.arange(4)
b=a #指向同一个对象
c=a.copy # 指向各自的对象
d=a.view()
d is a # False
d.base is a # True
d.flags.owndata # False
a[0]=100
b
c

映射函数

1
2
# 可针对某个轴的方向进行函数操作
apply_along_axis()

添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import numpy as np

arr = np.array([[1, 3, 5], [2, 4, 6]])
# 添加元素
print(np.append(arr, [1, 1, 3]))
# 沿 0 轴添加元素
print(np.append(arr, [[1, 1, 3]], axis=0))
# 沿 1 轴添加元素
print(np.append(arr, [[1, 1, 3], [2, 1, 5]], axis=1))

import numpy as np

arr = np.array([[1, 3, 5], [2, 4, 6]])
# 添加元素
print(np.insert(arr, 1, [1, 1, 3]))
# 沿 0 轴添加元素
print(np.insert(arr, 1, [1, 1, 3], axis=0))
# 沿 1 轴添加元素
print(np.insert(arr, 1, [1, 5], axis=1))


import numpy as np

arr = np.array([[1, 3, 5], [2, 4, 6]])
# 删除元素
print(np.delete(arr, 1))
# 沿 0 轴删除元素
print(np.delete(arr, 1, axis=0))
# 沿 1 轴删除元素
print(np.delete(arr, 1, axis=1))

组合与拆分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
a=np.arange(6).reshape(2,3)
b=np.arange(3,9).reshape(2,3)

# 竖直,vertical stack,上下/垂直方向合并,沿第一个轴组合
np.vstack((a,b))
# 水平, horizontal stack 左右/水平方向合并,沿第二个轴组合
np.hstack((a,b))

# 堆叠
np.dstack((a,d))


np.column_stack((a,b)) # 以序列的顺序将多个一维数组或一个二维数组按对位组合成新的二维数组

np.r_ 是按列连接两个矩阵,就是把两矩阵上下相加,要求列数相等。
np.c_ 是按行连接两个矩阵,就是把两矩阵左右相加,要求行数相等。

np.concatenate((a,b),axis=1) # 行,水平
c=np.concatenate(a,b,b,axis=1)

np.hsplit(a,3)
np.split(a,3) #三均分
np.hsplit(a,(3,4))
np.split(a,[3,5,6,10])#分成 0-3,4-5,6,7-10
np.vsplit(a,2)
a=np.arange(12).reshape(3,4)
print(a)
print(np.split(a,2,axis=1)) #均分两块
print(np.array_split(a,3,axis=1)) #均分 3 块分不过来,得用这个
print(np.vsplit(a,3))
print(np.hsplit(a,2))


# 复制
np.title(a,(2,3))

# array([[1, 2],
# [3, 4]])
# array([[1, 2, 1, 2, 1, 2],
# [3, 4, 3, 4, 3, 4],
# [1, 2, 1, 2, 1, 2],
# [3, 4, 3, 4, 3, 4]])
a.repeat(3,axis=1)
# array([[1, 1, 1, 2, 2, 2],
# [3, 3, 3, 4, 4, 4]])

删除与插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 删除
np.delete(a,[1,3],axis=1)
np.delete(a,s_[1:-1],axis=1)
np.delete(a,slice(1,-1),axis=1)


# 插入
np.insert(a,[1,2],0,axis=1)
np.insert(a,1,7,axis=0)

# append
np.append(a,np.zeros(3,2),axis=1)
np.column_stack(a,np.zeros(3))
#
np.pad(a,(0,1,(0,0)),constant_values=1) # 0 1 0 0 表示上下左右,示例为在下方加一层1
np.pad(a,1) # 在它的周围加一层0

更改形状

1
2
3
4
5
6
7
8
9
10
11
12
13
a=np.arange(24).reshape(2,3,4)
# 返回修改后的数组,不更改原数据
b=a.ravel() # 一维数组,扁平化数组
b=a.reshape(3,4) # 改变到新的 shape
b=a.reshape(4,-1) # -1 会自动计算其他的 size 大小
b=a.T # 完全转置,a.transpose(2,1,0)
a.transpose(1,0,2)

# 改变原数组
a.resize((2,6))

# 对每个元素进行操作
b.flat # 一维数组的 iterator

排序

1
2
3
a.sort()
np.sort(a)
a.sort(axis=-1)

选择

  • 输入输出
  • 离散傅立叶变换
  • 线性代数
  • 统计运算
  • 随机模拟
1
2
import numpy as np
np.set_printoptions(suppress=True)

随机数

随机种子:确定随机种子,即确定随机数的起点:随机数是一长序列,设定随机种子,相当于设定了序列的起点,后面生成的随机数相同

1
2
3
4
5
6
7
8
9
10
11
12
np.random.seed(0) # 确定随机种子,即随机数的起点
np.random.randn(1,5)
# array([[1.76405235, 0.40015721, 0.97873798, 2.2408932 , 1.86755799]])
np.random.randn(1,5)
# array([[-0.97727788, 0.95008842, -0.15135721, -0.10321885, 0.4105985 ]])

np.random.seed(0) # 再次设定随机种子
np.random.randn(1,5)
# array([[1.76405235, 0.40015721, 0.97873798, 2.2408932 , 1.86755799]])
np.random.randn(1,5)
# array([[-0.97727788, 0.95008842, -0.15135721, -0.10321885, 0.4105985 ]])

广播 Broadcasting

  • broadcast 提供了一种向量化阵列的操作方式,因而减少了循环,通常执行效率非常高。然而,有时可能会导致内存浪费以致计算减慢。
  • Numpy 的 Universal functions 中要求输入的数组 shape 是一致的,当数组的 shape 不想等的时候,则会使用广播机制,调整数组使得 shape 一样,满足规则,则可以运算,否则就出错。
1
2
3
4
a = np.array([1.0, 2.0)
b = 2.0
a * b
array([ 2., 4.])

解线性方程组

1
2
3
4
5
A = np.mat("1 -2 1;0 2 -8;-4 5 9") # 矩阵
B = np.array([0,8,-9]) # 数组
x = np.linalg.solve(A,B)
print (x)
#[ 29. 16. 3.]

linalg

linear(线性)+algebra(代数),

1
2
3
4
5
6
7
8
9
np.linalg.inv(a)
array([[-2. , 1. ],
[ 1.5, -0.5]])

# 范数
x_norm=np.linalg.norm(x, # 矩阵
ord=None, # 范数类型
axis=None,
keepdims=False)

遇到的问题

  • 问题:Opencv的两像素相减,不会出现负值,而是都在[0-255]之间
  • 解决方案:
1
imgs_train[1][:,:,1].astype(np.float32)-imgs_train[1][:,:,2].astype(np.float32)

pandas

pandas:[‘pændəz],基于 Numpy 开发,提供高性能、高级、易使用的数据结构与各种数据分析工具。

  • 特点:
    • 突破:只要内存够大,可以完全代替 SQL。
    • 相比于 numpy 的列表式数据,pandas 的字典式数据更好操作
    • 将复杂的数据操作转换为一两条命令
    • 可作为数据库框架使用
    • 开源:BSD 协议
  • 高效:快速、灵活、明确
  • 参考资料
  • 功能
    • 进行 dataframe 处理
    • 合并、去重、转换、汇总、分组
  • 适用于处理以下类型的数据:
    • 有序和无序的时间序列数据
    • 带行列标签的矩阵数据,包括同构或异构型数据
    • 与 SQL 或 Excel 表类似的,含异构列的表格数据
    • 任意其它形式的观测、统计数据集,数据转入 Pandas 数据结构时不必事先标记
  • 劝退:
    • pandas 加一行数据,万级的数据量,无论是用 loc 还是 concat,都是秒级,append,是毫秒级;pandas、又重又慢
1
2
3
4
5
6
7
8
df.loc[0]={'a':1,'b':2}

#新建一个df
df2 = pd.DataFrame(['999999','空',5]).T
# 修改df2的column和df的一致
df2.columns = df.columns
# 把两个dataframe合并,需要设置 ignore_index=True
df = pd.concat([df2,df], axis=0 ,ignore_index=True) #参数axis=0表示上下合并,1表示左右合并,ignore_index=True表示忽略原来的索引

名词解释

column:列
row:行

数据结构

pd.Seriespandas 数组(列表),均匀数据的一维数组

  • pd.date_range:创建 pandas 日期列表
1
2
3
4
5
6
7
8
9
10
11
import pandas as pd
import numpy as np

# 创建
s1 = pd.Series([1,2,3,4,np.nan,5,6]) # 从数组创建 Series
s2=pd.Series(np.random.randn(5),index=['a','b','c','d','e']) # 从 ndarray 创建 Series
s3=pd.Series({'a':1,'b':2,'c':3}) # 从字典创建 Series

# 时间
dates=pd.date_range('20210101',periods=7) # pandas.core.indexes.datetimes.DatetimeIndex
df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list("ABCD"))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 属性
s1.index # 获取索引
s1.values # 获取值
s1.iteritems # 获取索引与值

# 取值
s2[0]
s2['a']
s2[1:3]
s2['b':'d']
s2[[1,4]] # 取不连续值
s2[['b','d']]

# 操作
s1.append(s2)
s3.drop('a')
s3['b']=6
s3[:3]

s1+s2
s1-s2
s1*s2
s1/s2
s1.add(s2)
s1.sub(s2)
s1.mul(s2)
s1.div(s2)

s1.median() # 中位数
s1.sum() # 求和
s1.max()
s1.min()

pd.DataFrame

pd.DataFrame:pandas 矩阵,异构数据的二维数组,Series 的容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 创建
df_test=pd.DataFrame(columns=['学生 ID','姓名','年龄'])
df1=pd.DataFrame(np.random.randn(5,5),index=list('abcde'),columns=list('abcde'))

dates=pd.date_range('20200101',periods=6)
df=pd.DataFrame(np.random.randn(6,4),index=dates,columns=list('ABCD'))

# 使用字典来创建
dict1={'name':['zhang','chen','li'],'age':[20,18,25]}
df2 = DataFrame(dict1)

# 以 dict 的 key 作为行标题
DataFrame.from_dict(
data_dict, # dict,数据
orient='columns', # dict 的 key 作为行标题'index'还是列标题'columns'
dtype=None,
columns=None
)
df3 = DataFrame.from_dict(dic,orient='index')
print(df3)
# 转为字典
d = df3.to_dict()

属性

1
2
3
4
5
6
7
8
9
10
11
12
df.info() # 基本信息,维度,列名称,数据格式,空间
df.index # 行名
df.columns # 列名
df.values # 数据表的值
df.count # 每一列有多少数据
df.isnull() #查看空值
df.describe() # 实值数据列的统计数据,基本统计信息(基于列计算):count、mean、std、min、25%、50%、75%、max。
df.shape # 维度,行数与列数
df.T # 转置

df.dtypes # 每列的数据类型
df['id'].dtype

操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 查
df['id'].unique() # 唯一值

df.head(n=20) #默认为前 5 行
df.tail(5) # 后 5 行

df['id'].count() # 计数

# 数据
df['name'] # name 列,Series
df[['name','age']] # 多列
df[1:2] # 一行
df[1:4] # 多行
df[1:4][['name']] # 多行的某一列
df.loc[1,'name'] # 某一行的某一列
df.loc[1,['name','age']] # 某一行的指定列
df.loc[1,:] # 某一行的所有列
df.loc[0:2,['name','age']] # 多行的多列
df.loc[[0,2],['name','age']]
df.iloc[1] # 取一行
df.iloc[0:3] # 取多行
df.iloc[:,0] # 取某列
df.iloc[0,1] # 取某个值

# 增
df1 = DataFrame([['张三', '22'], ['李四', '33'], ['王五', '11']], columns=['name', 'age'])
df2 = DataFrame([['张三', '22'], ['李四', '33'], ['王五', '11']], columns=['name', 'age'])
# 在某位置插入一列
# 方式 1
col = df1.columns.tolist()
col.insert(1, 'gender')
df1.reindex(columns=col)
df1['gender'] = ['男', '女', '保密']
print(df1)
# 方式 2
df1.insert(0, 'id', ['001', '002', '003'])
print(df1)
# 在某位置插入一行
row = ['004', '赵六', '66', '男']
df1.iloc[2] = row
print(df1)
df3 = DataFrame({'name':'赵六', 'age':'55'}, index=[0])
df2 = df2.append(df3, ignore_index=True)
print(df2)
# 合并
df4 = DataFrame(np.arange(6).reshape(3, 2), columns=['a', 'b'])
df5 = DataFrame(np.arange(6).reshape(2, 3), columns=['c', 'd', 'e'])
# 按行
pd6 = pd.concat([df4, df5], axis=1)
print(pd6)
# 按列
pd7 = pd.concat([df4, df5], axis=0, ignore_index=True)
print(pd7)
'''
删除
参数 1:要删除的标签
参数 2:0 表示行,1 表示列
参数 3:是否在当前 df 中执行该操作
'''
df5.drop(['c'], axis=1, inplace=True)
print(df5)
df5.drop([1], axis=0, inplace=True)
print(df5)

pd.Panel

pd.Panel: 面板,异构数据的三维数组,DataFrame 的容器

  • pd.Panel4D:四维数组
  • pd.PanelND…更多维数组

数据类型

  • float:float64:浮点数字
    • 浮点数默认类型
  • int:int64:整型数字
    • 整数默认类型
  • bool:True/False
  • datetime64:日期时间
  • timedelta64:时间差
  • category:枚举
  • object:文本或混合数字
    • 文字默认类型
  • string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# DatetimeTZDtype
# 时区为北京时间,单位支持纳秒
d = pd.DatetimeTZDtype("ns", tz='Asia/Shanghai')
pd.Series(['20200501 22:23:22.3432'], dtype=d)
# 0 2020-05-01 22:23:22.343200+08:00
# dtype: datetime64[ns, Asia/Shanghai]

pd.Series(['20200501 22:23:22.3432'], dtype='datetime64[ns, Asia/Shanghai]')
pd.Series(['20200501 22:23:22.3432'], dtype='datetime64[ns]') # 无时区
# 用字符形式
pd.Timestamp('2017-01-01T12')
# Timestamp('2017-01-01 12:00:00')

# Unix epoch 指定时间单和时区
pd.Timestamp(1513393355.5, unit='s')
# Timestamp('2017-12-16 03:02:35.500000')
pd.Timestamp(1513393355, unit='s', tz='US/Pacific')
# Timestamp('2017-12-15 19:02:35-0800', tz='US/Pacific')

# 用 datetime.datetime 的方法
pd.Timestamp(2017, 1, 1, 12)
# Timestamp('2017-01-01 12:00:00')
pd.Timestamp(year=2017, month=1, day=1, hour=12)
# Timestamp('2017-01-01 12:00:00')

# 枚举
t = pd.CategoricalDtype(categories=['b', 'a'], ordered=True)
pd.Series(['a', 'b', 'a', 'c'], dtype=t) # 'c' 不在列表是值会为 NaN
'''
0 a
1 b
2 a
3 NaN
dtype: category
Categories (2, object): [b < a]
'''

pd.Categorical(['a', 'b', 'c', 'a', 'b', 'c'])
# [a, b, c, a, b, c]
# Categories (3, object): [a, b, c]


# 时间周期
pd.PeriodDtype(freq='D') # 按天
# period[D]
pd.PeriodDtype(freq=pd.offsets.MonthEnd()) # 按月,最后一天
# period[M]


# 字符串
pd.Series(['a','b','c'], dtype=pd.StringDtype())
'''
0 a
1 b
2 c
dtype: string
'''

pd.api.types.is_bool_dtype(s)
pd.api.types.is_categorical_dtype(s)
pd.api.types.is_datetime64_any_dtype(s)
pd.api.types.is_datetime64_ns_dtype(s)
pd.api.types.is_datetime64_dtype(s)
pd.api.types.is_float_dtype(s)
pd.api.types.is_int64_dtype(s)
pd.api.types.is_numeric_dtype(s)
pd.api.types.is_object_dtype(s)
pd.api.types.is_string_dtype(s)
pd.api.types.is_timedelta64_dtype(s)
pd.api.types.is_bool_dtype(s)

# 选择指定数据类型的列
df.select_dtypes(include=['number', 'object'])

基本操作

基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import pandas as pd

pd.get_option()
pd.set_optioin()
pd.reset_optioin()
pd.reset_option('all') # 重置所有设置选项
# 打印出设置的描述及其当前值
pd.describe_option()


# 显示所有列(参数设置为 None 代表显示所有行,也可以自行设置数字)
pd.set_option('display.max_columns',None)
pd.set_option('display.max_columns',20) # 显示20列

# 显示所有行
pd.set_option('display.max_rows',None)
pd.set_option('display.max_rows',200) # 显示200行

# 列宽,设置数据的显示长度,默认为 50
pd.set_option('max_colwidth',200)

# 禁止自动换行(设置为 Flase 不自动换行,True 反之)
pd.set_option('expand_frame_repr', False)

# 设置float的精度,默认小数点后6位
pd.set_option('display.precision',2)

# 不采用科学计数法
pd.set_option('display.float_format',lambda x:'%.5f'%x)
# 数字格式化显示
pd.set_option('display.float_format','{:,}'.format)
pd.set_option('display.float_format', '{:,.2f}'.format)
pd.set_option('display.float_format', '{:.2f}%'.format) # 添加百分比


# 更改绘图方法
import pandas as pd
import numpy as np
pd.set_option('plotting.backend', 'altair')
data = pd.Series(np.random.randn(100).cumsum())
data.plot()


数据加载与导出

  • 读写 excel 需要 xlrd 与 xlwriter 模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# 读入
df1=pd.read_csv("aa.csv",header=0,encoding='gbk')
df2=pd.read_excel('aa.xlsx')
df3=pd.DataFrame({"id":[1001,1002,1003,1004,1005,1006],
"date":pd.date_range('20130102', periods=6), #日期列表
"city":['Beijing ', 'SH', ' guangzhou ', 'Shenzhen', 'shanghai', 'BEIJING '],
"age":[23,44,54,32,34,32],
"category":['100-A','100-B','110-A','110-C','210-A','130-F'],
"price":[1200,np.nan,2133,5433,np.nan,4432]},
columns =['id','date','city','category','age','price'])
con = sqlite3.connect('...')
f = pd.read_sql('select * from student;',con=mysql_conn)

# 导出
df.to_csv('my_csv.csv', mode='a', header=False)
df.to_csv('aa.csv',encoding=’gbk’,sep=',',header=True,index=False) #index=False 表示导出时去掉行名称,如果数据中含有中文,一般 encoding 指定为‘utf-8’

df.to_excel('new_aa.xlsx',sheet_name='test')
data=pd.read_csv(csv_path,encoding="gbk",quoting=csv.QUOTE_NONE)
#pandas 使用 read_csv 读取文件时产生错误:EOF inside string starting at line 解决方法:使用参数 quoting

# 牛*,将剪贴板中的数据通过read_table()转为 dataframe
pd.read_clipboard()
#SQL table/database
pd.read_sql(query,connection_object)

#delimited txt file(like TSV)
pd.read_table(filename)

# json formatted string, URL or file
pd.read_json(json_string)

# html URL, string or file or tables
pd.read_html(url)

excel_writer = pd.ExcelWriter('output.xlsx')
df_data.to_excel(
'test.xls', # 现有的文件路径或 ExcelWriter
sheet_name='NewSheet',
na_rep='', # 缺少数据的表现形式
float_format=None, # 格式化浮点数字符串
columns=None, # 将指定列写入
headers=True, # 写入列名
index=True, # 写入索引
index_label=None, # 引用索引列的列标签
startrow=0,
startcol=0,
engine=None, # openpyxl 或 xlsxwriter
merge_cells=True, # MultiIndex 和 Hierarchical 行写为合并的单元格
encoding=None, # 指定编码,对 xlwt 是必需的
inf_rep='inf' # 无穷大
verbose=True,
freeze_panes=None # 要冻结的最底部一行和最右边一列

)
excel_writer.save()


# 写入csv
df.to_csv(filename)

# 写入excel
df.to_excel(filename)

# 写入sql表
df.to_sql(table_name, connection_object)

# 写入json文件
df.to_json(filename)

# 写入html
df.to_html(filename)

# 定入到剪贴板
df.to_clipboard()

数据提取

  • loc 函数按标签值进行提取
  • iloc 按位置进行提取
  • ix 可以同时按标签和位置进行提取。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
data_df     # 选择所有
data_df["student_id"] # 指定列,同 df.student_id
data_df[['name','age']]
data_df[1:5] # 指定行

data_df.loc[3] # 索引为 3 的行
data_df.loc[行索引,列名] # 根据行名和列名选择数据



# 索引操作
data_df.iloc[行索引选择, 列索引选择]:根据行索引和列索引选择数据
data_df.iloc[1:3,2:4]
data_df.iloc[[0,2],1:3]
# ix
ix[行 名/索引 选择,列 名/索引 选择]:混合 名/索引 选择数据
# 布尔表达式:布尔表达式为真的数据会被选择
data_df[data_df.student_id >3]
data_df.name
data_df['name']

# 取多列
data_df[['name','age']]

# 去除重复: select distinct name from data_df
data_df['name'].drop_dumplicates()

# 条件限定:每个条件要用括号()括起来。
data_df[data_df[“name”].isin([“zhang”,’chen’]) & data_df[“age”].isin([18,19,20])]
data_df[data_df[‘age‘]<=18]
data_df[data_df['name'].isin(['chen','zhang'])]
# 替换
data_df['age']=data_df['age'].replace(-1,0)
data_df['name']=data_df['name'].replace('chen','zhang')
data_df['new_book']=data_df['book'].applay(lambda book:book.lower())
data_df['age2']=data_df['age']*2
print(f.ix[10:20, 0:3]) #打印 10~20 行前三列数据
print(f.columns) #列名
print(f.index) #行名
#提取不连续行和列的数据,这个例子提取的是第 1,3,5 行,第 2,4 列的数据
f.iloc[[1,3,5],[2,4]]
#example:假设我们要筛选出小费大于$8 的数据
data_df[f.tip>8]
#数据筛选同样可以用”或“和”且“作为筛选条件,比如
#1
data_df[(data_df.tip>7)|(data_df.total_bill>50)] #筛选出小费大于$7 或总账单大于$50 的数据
#2
data_df[(data_df.tip>7)&(data_df.total_bill>50)]#筛选出小费大于$7 且总账单大于$50 的数据

age_no_na = titanic[titanic["Age"].notna()]

数据处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
df1.sort_index(axis=1,ascending=False)
矩阵排序{axis:0(行排序),1(列排序)}
{ascending:True(升序),False(降序)}
sort_values(by=, ascending=):按某一列的值排序{by:列名}

# 百分比显示数据
data[u'线损率'] = data[u'线损率'].apply(lambda x: format(x, '.2%'))

# 计算各列数据总和并作为新列添加到末尾
df['Col_sum'] = df.apply(lambda x: x.sum(), axis=1)

#计算各行数据总和并作为新行添加到末尾
df.loc['Row_sum'] = df.apply(lambda x: x.sum())

数据清洗

重命名

1
2
3
4
5
6
7
8
9
10
11
12
# 列名
df.rename(columns={'name':'student_name'},
inplace=True) # 在当前datframe上修改

df.rename(indexs={'name':'student_name'}) # 改名

# 暴力全改,有多少个 columns 就得写多少项
df_data.columns=['学号','姓名','年龄']
# 指定 一对一的修改
df_data.rename(columns={'stu_no':'学号', 'stu_name':'姓名', 'age':'年龄'}, inplace = True)

df1 = df1.where(df1.notnull(), '')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
df=df.fillna(value=0)  # 空值填 0
df['age'].fillna(df['age'].mean()) # 均值填
df['city']=df['city'].map(str.strip) #函数操作
df['city']=df['city'].str.lower()
df['price'].astype('int') #改数据类型

df['city'].drop_duplicates() #删除后出现的重复值
df['city'].drop_duplicates(keep='last') #删除先出现的重复值
df['city'].replace('sh','shanghai')
df.describe() #叙述性统计
df['age'].hist() #直方图
df["alcass"].unique() #唯一值
df["name"].read()
df[df["sex"]=="female"].head()#筛选数据
df.sort_values("age",ascnding=False).head()
df.iloc[0,1] #指定位置的数据
# 以 values 排序,以 index 排序
df.sort_values(['age'],ascending=False) #ascending=True 默认升序
df.['age'].mean()
df.loc['name':'age'] #按 label 取数据 name 到 age 间的多列
df.iloc[1:4,2:3]# 行切片,列切片



df.sum() # 每一列的求和
df.cumsum() # 前n行的累积求和
df.cumsum(axis=0, skipna=True, level=NaN)返回样本的累计和
df.cummax() # 前n行的最大值
df.cummin() # 前n行的最小值

df.min() # 每一列的最小值
df['age'].idxmin() # 最小值对应的索引
df.max() # 每一列的最大值
df['age'].idxman() # 最大值对应的索引
df.mean() # 每一列的均值
df.median() # 每一列的中位数
df.quantile([0.25, 0.75]) # 每一列中的25%和75%的分位数
df.var() # 方差值
df.std() # 标准差值
df.corr() # 列之间的相关系数
1
2
3
4
5
6
7
8
dates = pd.date_range('20180709', periods=3)
df = pd.DataFrame(np.arange(12).reshape((3, 4)), index=dates, columns=['A', 'B', 'C', 'D'])
df.loc['20180709', 'B'] = 666
df.iloc[2, 2] = 999
df.ix['20180709', 3] = 777
df.A[df.A > 3] = 888
df['F'] = np.nan
print(df)

数据清洗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 合并
df_merge = pd.merge(
df1, # 待合并的矩阵
df2, # 待合并的矩阵
how='left', # 处理非公有行的方式,inner:去除非公有行,outer:对非公有的行进行 NaN 值填充然后合并,left:保留左矩阵的所有行,对非公有的元素进行 NaN 值填充,right:保留右边矩阵的所有行,对非公有的元素进行 NaN 值填充
left_on='student_id',
right_on='student_id')
on:公有列名
indicator:是否显示每一行的 merge 方式
suffixes:非公有列的列名后缀

air_quality = pd.merge(air_quality, air_quality_parameters,
how='left', left_on='parameter', right_on='id')
table_1.merge(table_2, left_on='lkey', right_on='rkey', how='left')

# 全连接,UNION ALL
final_table = pd.concat([table_1, table_2])
air_quality_ = pd.concat([air_quality_pm25, air_quality_no2], keys=["PM25", "NO2"], axis=0)

data_df[data_df['column_a'].str.contains('ball')]
data_df[data_df['column_a'].isin(['Canada', 'USA'])]
data_df.sort_values('column_a',
ascending=False) # 升序还是降序
# 多列排序
data_df.sort_values(['column_a', 'column_b'],
ascending=[False, True])

# 聚合函数
data_df.groupby('column_a')['ID'].nunique()
data_df.groupby(['column_a', 'revenue']).sum()
data_df.groupby('column_a')['revenue'].mean()

HDF5

HDF5:Hierarchical Data Format:高效存储和分发科学数据的新型数据格式

  • 特点:
    • 自述性:文件内的每个数据对象都有元数据
      • 数据对象 = 数据描述符 + 数据元素
        • 数据描述符:12 字节长,包含了数据元素的类型、位置、尺度等信息
        • 数据元素:数据部分
    • 通用性:兼容各种数据类型
    • 灵活性:相关数据可组合,放到一个分层结构,向数据对象添加描述和标签
    • 扩展性:易增加新的数据模式、与其他标准格式兼容
    • 跨平台:与平台无关
  • 文件构成:基本数据对象
    • group:包含 0 个或多个 HDF5 对象且支持元数据(metadata)的一个群组结构
    • dataset:数据元素的一个多维数组及支持元数据(metadata)
  • 数据类型:
    • 栅格图象: 数据模式提供一种灵活方式存储、描述栅格图象数据,包括 8bit 栅格图象。
    • 调色板: 也叫作彩色查对表,它提供图像的色谱。
    • 科学数据集: 用来存储和描述多维科学数据陈列。
    • Vdata: 是一个框架,用于存储和描述数据表。
    • HDF 注释: 是文字串,用来描述 HDF 文件或 HDF 数据目标。
    • Vgroup: 是用来把相关数据目标联系起来。一个 Vgroup 可以含有其它 Vgroup,以及数据目标。任一个 HDF 目标均可以包括进某个 Vgroup 中。
  • 性能:
    • 在写出同样大小的数据框上,HDF5比常规的csv快了将近50倍, and csv比HDF5多占用将近一倍的空间,这还是在我们没有开启HDF5压缩的情况下
1
2
3
# 类似dict的对象,使用PyTables库以高性能的HDF5格式来读写pandas对象
pd.HDFStore(hdf5_path,
'w')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import pandas as pd
####生成9000,0000条数据,9千万条
a = np.random.standard_normal((90000000,4))
b = pd.DataFrame(a)
####普通格式存储:
h5 = pd.HDFStore('/data/stock/test_s.h5','w')
h5['data'] = b
h5.close()

####压缩格式存储
h5 = pd.HDFStore('/data/stock/test_c4.h5','w', complevel=4, complib='blosc')
h5['data'] = b
h5.close()

data=pd.read_hdf('/data/stock/test_c4.h5',key='data')

Scipy

SciPy:科学计算包: 解决线性代数、概率论、积分等任务的工具

fortran 数值计算库

  • SciPy 包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。其功能与软件 MATLAB、Scilab 和 GNU Octave 类似。
  • 线性代数使用 lapack 库
    • fftpack 库:快速傅里叶变换
    • odepack 库:常微分方程求解
    • minpack 库:非线性方程组求解及最小值求解。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 数值积分例程和微分方程求解器
scipy.integrate

# 线性代数例程和矩阵分解
scipy.linalg

# 函数优化器与根查找算法
scipy.optimize

# 信号处理工具
scipy.signal

# 稀疏矩阵和稀疏线性系统求解器
scipy.sparse

# 常用数学函数的 Fortran 库的包装器
scipy.special

# 标准连续与离散概率分布、各种统计检验 方法及更好的描述统计法
scipy.stats

# 以内联 C++代码加速数组计算的工具
scipy.weave

blaze

blaze:Python 数据值计算库,号称下一代的 Numpy

  • 用于处理分布式的各种不同数据源的计算

shapely

shapely:操作和分析笛卡尔坐标系中的几何对象,使用GEOS库中的函数进行矢量数据构建与分析

#最佳实践

  • Shapely 实现没有 平滑(即具有连续切线)曲线。所有曲线必须 由线性样条近似
  • 各种几何对象的属性
    • 面积:area:float
    • 边界:bounds:float的(minx,miny,maxx,maxy)
    • 长度:length:float
    • 返回可移动节点以产生无效几何图形的最小距离:minium_clearance
      • 不存在则返回 math.infinity
    • 类型:geom_type:str
    • 距离:obj.distance(other):到另一个几何对象的最小距离
    • hausdorff距离:obj.hausdorff_distance(other):最远距离
    • representative点:obj.representative_point():返回
      • 不是质心(centroid)
    • 转换为wkt格式:obj.wkt
    • 是否为空:obj.is_empty
    • 是否包含Z坐标:obj.has_z
    • 是否是有效对象:obj.is_valid
    • 对像的小最小凸多边形:obj.convex_hull
    • 对象的最小矩形:obj.envelope
    • 对象的最小外接矩形:obj.minimum_rotated_rectangle
    • 对象左侧或右侧的一个LineString或MultiLineString:obj.parallel_offset(distance,side,resolution=16,join_style=1,mitre_limit=5.0)
  • 点的处理:
    • 获取点的坐标:point.coords[:]

实体类

点-Point

  • 点的集合:MultiPoint
    • list(points.geoms):访问点集合的成员

线-LineString

  • 线的集合:MultiLineString
  • 坐标:line.coords
  • 是否为闭环:line.is_ring
  • 是否是简单的:line.is_simple

线性环:LinearRing

线性环不能交叉,也不能相互接触 在一个点上

  • 坐标:ring.coords
  • 坐标是否为逆时针:ring.is_ccw
  • 是否为闭环:ring.is_ring

多边形-Polygon-曲面

  • 曲面的集合:MultiPolygon
  • 获取多边形的外环坐标:polygon.exterior.coords
    • 即多边形上的点:points = list(polygon.exterior.coords)
  • 获取多边形的内环:polygon.interiors
1
2
3
4
5
6
7

coords = [(0, 0), (1, 1), (1, 0)]
r = LinearRing(coords)
s = Polygon(r)
s.area

t = Polygon(s.buffer(1.0).exterior, [r])

矩形多边形-box

  • 默认为逆时针顺序
1
2
from shapely import box

集合

  • 获取集合中各对象的类型:
    • collection.geoms
    • list(collection.geoms)
    • len(collection.geoms)
  • 除collection类型为,其它集合类型如Multipoint、MultiLineString、MulitPolygon也支持这些操作。

关系

  • 包含
  • 相交
  • 重叠

操作

获取两个对象的关系

  • 是否完全相同:类型和坐标都相同:object.__eq__(other)
  • 是否相同:边界、interior和exterior相同:object.equals(other)
  • 是否近似相同:object.almost_equals(other[, decimal=6])
  • 是否包含:object.contains(other)
  • 是否反向包含:object.within(other)
  • 是否交叉:object.crosses(other)
  • 是否反向交叉:object.disjoint(other)
  • 是否交叉:object.intersects(other)
  • 是否覆盖:object.overlaps(other)
  • 是否接触:object.touches(other)

创建新的对象

  • 差集:object.difference(other)
  • 交集:object.intersection(other)
  • 对称差集:object.symmetric_difference(other)
  • 并集:object.union(other)

Polars

polars:Polars 是一个用于处理结构化数据的极速 DataFrame 库。其核心用 Rust 编写,并提供 Python、R 和 NodeJS 接口。

  • 特点:
    • 快速:完全用 Rust 从头编写,设计贴近底层机器,无外部依赖。
    • I/O (输入/输出):对所有常见数据存储层提供一流支持:本地、云存储和数据库。
    • 直观的 API:以您预期的方式编写查询。Polars 会利用其查询优化器在内部确定最有效的执行方式。
    • 核外处理:流式 API 允许您处理结果,而无需将所有数据同时加载到内存中。
    • 并行:通过在可用 CPU 核心之间分配工作负载,充分利用您机器的性能,无需额外配置。
    • 向量化查询引擎
    • GPU 支持:可选地在 NVIDIA GPU 上运行查询,以在内存工作负载中实现最大性能。
    • Apache Arrow 支持:Polars 可以消费和生成 Arrow 数据,通常进行零拷贝操作。请注意,Polars 不是基于 Pyarrow/Arrow 实现构建的。相反,Polars 有自己的计算和缓冲区实现。
  • 理念:目标是提供一个闪电般快速的 DataFrame 库
    • 利用您机器上的所有可用核心。
    • 优化查询以减少不必要的工作/内存分配。
    • 处理远大于可用 RAM 的数据集。
    • 提供一致且可预测的 API。
    • 遵循严格的模式(数据类型在运行查询前应已知)。
  • 支持:
    • Polars 支持常见文件格式(例如 CSV、JSON、Parquet)、云存储(S3、Azure Blob、BigQuery)和数据库(例如 PostgreSQL、MySQL)的读写。
给博主来一杯卡布奇诺