前言
编程中,经常需要处理一堆数据,为了操作一堆数据 ,提供了几个基本的类型:set,tuple,list,dict, 以及常用的两个库numpy,pandas。在使用时,可能会迷糊,什么时候该用什么类型。本文是对这些知识的梳理。
对每一个类型,我们关注点都是 CRUD 操作,以及访问方法。
set 集合
set 与数学中的集合概念完全一样,由不重复元素组成。对于集合,我们关心的是集合中有什么元素 ,不关心次序,所以集合中没有按下标的访问方法。
set 支持并集,差集,交集的操作。
注意的是,所有set 中的元素必须是hashable类型,如何hashable 就不在此展开。
s1={1,2,3} # 创建
s1.remove(3) # 删除元素
s1.add(3) # 添加元素
s1.clear() # 清空
s1.add([1,2,3]) # 批量添加元素
s2={2,3,4}
s1.copy() # 复制
for x in s1: #访问所有元素
print(x)
s1 | s2 # {1,2,3,4} 并集
s1.union(s2) # 等于 s1 | s2
s1 & s2 # {2,3} 交集
s1.intersection(s2) # 相当于 s1 & s2
s1 ^ s2 # {1,4} 去除相同的元素,也就是交集的补集
s1.symmetric_difference(s2) # 等于 s1 ^ s2
s1-s2 # {1} 去除存在于s2中的元素
s2-s1 # {4} 去除存在于s1中的元素
s1.difference(s2) # 相当于 s1-s2 ,该操作不影响s1
# 以下带update的方法会修改原集合
s1.intersection_update(s2) # 相当于 s1 & s2
s1.difference_update_update(s2) # s1变成了{1}, 该操作影响s1
s1.symmetric_difference_update(s2)
s1={1}
s2={1,2}
1 in s1 # True 判断元素是否存在
s1<s2 # True ,s1属于s2
s1.issubset(s2) # 等于 s1<s2
s2>s1 # True, s2 包含 s1
s2.ssuperset(s1) # 等于 s2>s1
list 列表,数组
如果我们要记录一组按顺序的数据,比如每天的跑步公里数,按天形成了一个列表,就用list 。list 与set 的不同在于:
- list 可以按下标访问
- list 中元素可重复
- list 中元素可以是任何值
list 中的每个元素,相当于多了一个属性:顺序。 所以,list 中很多操作是和顺序相关,比如 reverse, sort, index,insert,append . 为了方便的访问元素,list 还提供了切片操作,这一点是特色。
# 创建
l = ['a','b','c']
l.copy()
l+l # ['a','b','c','a','b','c'] 支持加法,不支持减法
dl = l*3 # 相当于 l+l+l
#添加元素的操作,包括 append, insert
l.append('d')
l.extend(['e'.'f']) # 批量添加
l.insert('z',0) # 指定位置插入
#删除元素,包括remove ,pop ,del
l.remove('a') # 删除指定的元素,如果有多个,删除第一个
l.pop() # 删除最后一个
l.pop([1,2]) #删除指定位置的元素
del l[1] # 删除指定位置元素
#更新
l[0]='hello'
#获取,按下标获取,以及按切片获取一个新的list
l[0] # 第0个 ,list的下标是从0开始。
l[-1] # 最后一个
l[:] # 所有元素
l[1:] # 从下标
l[:2] # 从下标0至下标2,不包括2
l[1:3] # 从下标1到下标2,不包括3
tuple 元组
元组相当于不可变的list ,也就是创建后不能改变,其它操作与list 一样
t=(1,2)
t[0]=5 # 这是不允许的
dict 字典
如果我们希望给每个数据给一个名称,那就是字典:dict 。dict 保存的是 key,value 对。字典里的key不能重复,访问value 用key做下标 。
d = {"a":1,"b":2}
d['a'] #用下标访问
for key in d: # 访问所有元素
print(d[key])
d['a']=3 # 修改
del d['a'] # 删除
deque
collections.deque 提供了先进先出的操作,比list 多了一个 popleft() 方法
numpy
list 不具备科学计算能力,比如矩阵运算,数学统计。numpy 则提供了多维数组,及相应的统计,矩阵运算等,还支持复数操作,这些运算包括点乘,数乘,矩阵乘法,转置。从一个矩阵中切片 ,也相当方便。
数乘,点乘,与矩阵乘法
注意:矩阵乘法符号是@
from numpy import array
A=array([1,2]) # 创建一维数组
A*2 # 数乘
Out[4]: array([2, 4])
A*A # 点乘
Out[5]: array([1, 4])
A*A.T # 一维数组转置后还是一维数组
Out[6]: array([1, 4])
A@A.T # 一维数组转置后还是一维数组
Out[7]: 5
A.T@A # 一维数组转置后还是一维数组,所以矩阵乘法等同于点乘
Out[8]: 5
a=array([[1,2]]) # 创建二维数组
a.T@a # 矩阵乘法
Out[10]:
array([[1, 2],
[2, 4]])
A*a
Out[11]: array([[1, 4]])
A*a.T
Out[12]:
array([[1, 2],
[2, 4]])
聚合运算与AXIS 轴
如果需要按行,或者按列做聚合运算( 比如求和,求平均,求最大值, 求标准差),需要明白axis 的概念。x 轴(行)就是0,y轴(列)就是1
from numpy import array, max
m=array(
[[1,2,3],
[4,5,6],
[7,8,9]
])
m.sum() # 45, 不指定轴,所有元素相加
m.sum(axis=0) # 按行相加
Out[7]: array([12, 15, 18])
m.sum(axis=1) # 按列相加
Out[6]: array([ 6, 15, 24])
max(m,axis=1)
Out[20]: array([3, 6, 9])
叠代与切片
叠代可以按所有元素,或者按行,或列
切片的写法是 [开始:结束:步长]
m=array(
[[1,2,3],
[4,5,6],
[7,8,9]
])
m[1:3,1:3] # 取第2行到第3行,第2列到第3列
Out[28]:
array([[5, 6],
[8, 9]])
a = array([1,2,3,4,5,6])
a[0:6:2] # 步长 2
Out[26]: array([1, 3, 5])
矩阵运算
包括 dot,cross,outer,vdot,svg 等 ,可参看numpy 文档
pandas
如果我们想给每一行,或者每一列给一个名字的话,那么numpy 就不行了,得用pandas。pandas 提供两个基本的类:
- Series 一维的带标签的数组
- DataFrame 二维的,每行或每列都带标签 ,相当于excel中的表格
- Index 用来做索引
除此外,pandas 还能直接绘图
Series
from pandas import Series
s = Series([1,3,7,12])
s = Series([1,3,7,12,16],index=['a','b','c','d','e'])
#用数字切片
s[0]
s[0:3]] # 选出几个
s[[0,1,4]] # 任意选择
#用标签切片
s['a']
s[['a','e']]
s['a':'c']
s.describe() # 统计
Out[62]:
count 5.000000
mean 7.800000
std 6.220932
min 1.000000
25% 3.000000
50% 7.000000
75% 12.000000
max 16.000000
dtype: float64
s.plot() # 绘图
DataFrame
from pandas import DataFrame
trades={
'close':[1.2,1.11,1.16,1.13,1.09],
'open':[1.18,1.21,1.11,1.15,1.13],
'high':[1.22,1.24,1.18,1.17,1.15],
'low':[1.15,1.08,1.09,1.07,1.08]
}
dates=['2010-01-01','2010-01-02','2010-01-03','2010-01-04','2010-01-05']
pd= DataFrame(trades,index=dates) # 创建,给出数据,指明第行的标签。另外,pandas还支持从csv,excel格式的数据
pd
Out[9]:
close open high low
2010-01-01 1.20 1.18 1.22 1.15
2010-01-02 1.11 1.21 1.24 1.08
2010-01-03 1.16 1.11 1.18 1.09
2010-01-04 1.13 1.15 1.17 1.07
2010-01-05 1.09 1.13 1.15 1.08
pd['close'] # 按列名访问列
Out[10]:
2010-01-01 1.20
2010-01-02 1.11
2010-01-03 1.16
2010-01-04 1.13
2010-01-05 1.09
Name: close, dtype: float64
pd[['close','open']] #同时取两列
Out[16]:
close open
2010-01-01 1.20 1.18
2010-01-02 1.11 1.21
2010-01-03 1.16 1.11
2010-01-04 1.13 1.15
2010-01-05 1.09 1.13
pd.iloc[0] # 按行下标,访问一行
Out[24]:
close 1.20
open 1.18
high 1.22
low 1.15
Name: 2010-01-01, dtype: float64
pd.loc['2010-01-01'] # 按标签,访问一行
Out[25]:
close 1.20
open 1.18
high 1.22
low 1.15
Name: 2010-01-01, dtype: float64
pd.loc['2010-01-01':'2010-01-03'] # 按标签切片
Out[29]:
close open high low
2010-01-01 1.20 1.18 1.22 1.15
2010-01-02 1.11 1.21 1.24 1.08
2010-01-03 1.16 1.11 1.18 1.09
pd.describe() # 统计
Out[31]:
close open high low
count 5.000000 5.000000 5.000000 5.000000
mean 1.138000 1.156000 1.192000 1.094000
std 0.043243 0.039749 0.037014 0.032094
min 1.090000 1.110000 1.150000 1.070000
25% 1.110000 1.130000 1.170000 1.080000
50% 1.130000 1.150000 1.180000 1.080000
75% 1.160000 1.180000 1.220000 1.090000
max 1.200000 1.210000 1.240000 1.150000
pd.keys() # 所有列名称
Out[32]: Index(['close', 'open', 'high', 'low'], dtype='object')
pd.index # 得到索引
Out[33]: Index(['2010-01-01', '2010-01-02', '2010-01-03', '2010-01-04', '2010-01-05'], dtype='object')
pd.plot()