Pandas组队学习第一次学习任务
1. 匿名函数和map函数结合的运用
有 map(self, /, *args, ** kwargs)
->map(func, *iterables) --> map object
,参数func
即为将要进行操作函数,*iterables
为将要进行运算的可迭代对象即原始数据。返回结果为map object
可迭代map对象,此时可通过list
将map 对象值解析。
注意到将匿名函数使用在列表推导式中时,有(lambda x: ...)(*args)
。Pandas中有agg
,apply
函数。
2. 压缩函数和解压函数
enumerate
,zip
,使用时有for l_1, l_2 in zip(list_1, list_2)
,也可zip
和dict
函数快速建立两列表之间关系的字典形式。也可使用*
操作符对使用zip
打包后的数据进行解压。
3.numpy 创建数组
linespace
(指定个数,指定范围* 左右都为闭区间 );
arange
(指定步长,指定范围 左闭右开 *);
特殊形式矩阵创建函数:zeros
,eye
,ones
,full
;
array
(将其他类型数据转化为numpy.ndarray
型数据);
random.rand
(随机数组),random.randn
(标准正态分布随机数组), random.randint
(整数随机数组),random.choice
(满足限定条件下的随机数组).
4.numpy数组格式转换操作函数
.T
:转置函数.
.r_
:上下合并,使用时注意.r_[array_1, array_2]
使用[]
.
.c_
:左右合并, 使用时限制同.r_
,且一维数组和二维数组合并时,因一维数组默认为列向量因此只可以使用.c_
左右合并.
.reshape
:数组维度变换函数.
5.numpy数组切片索引操作
slice
型切片:即start:end:step
型索引方式.注意当对数组进行元素添加时,若start==end
时表示在start
处直接插入相应元素.
直接索引切片:通过指定维度索引的列表进行过索引切片.
np.ix_
:在对应维度上使用布尔型索引,此时无法使用slice
切片方式.
6.numpy数组其他操作函数
np.where
:查找符合描述的元素.
np.nonzero
,np.argmax
,np.argmin
:查找符合描述的元素对应索引.
np.any
,np.all
:前者判断是否存在元素符合描述,后者判断是否全体元素符合描述.
np.cumprod
,np.cumsum
:前者为元素累乘函数,后者为元素累加函数.
np.diff
:当前元素同前一元素做差,默认长度为原数组长度减1,原因为首元素为[1]与[0]做差所得,即原数组中首位元素无前置元素.
统计函数:max
,min
,mean
,median
,std
,var
,sum
,quantile
(分位数), 注意:对元数据进行统计时若需要忽略Nan值则需要使用以上统计函数的nan*
类型函数.
cov
:协方差函数.
corrcoef
:相关系数函数.
7.numpy的广播机制
注意:当两个一维数组的维度分别为(m×1),(1×n),通过广播机制可得到(m×n)维度数据.
8.向量与矩阵运算
dot
:向量内积函数.
@
:矩阵运算操作符.
np.linalg.norm
:向量范数和矩阵范数(此运算函数包括内容使用时需要根据需求查询对应参数)
#练习1
M1 = np.random.rand(2, 3)
M2 = np.random.rand(3, 4)
res = np.array([[sum(m2 * m1) for m2 in M2.T] for m1 in M1])
print(((M1@M2 - res) < 1e-5).all())
True
#练习2
A = np.arange(1,10).reshape(3, 3)
B = A * (1/A).sum(axis = 1).reshape(-1,1)
B
array([[ 1.83333333, 3.66666667, 5.5 ],
[ 2.46666667, 3.08333333, 3.7 ],
[ 2.65277778, 3.03174603, 3.41071429]])
# 练习3
np.random.seed(0)
A = np.random.randint(10, 20, (8, 5))
B = A.sum(0) * A.sum(1).reshape(-1,1) / A.sum()
chi = ((A - B)**2 / B).sum()
chi
11.842696601945802
# 练习4
np.random.seed(0)
m, n, p = 100, 80, 50
B = np.random.randint(0, 2, (m, p))
U = np.random.randint(0, 2, (p, n))
Z = np.random.randint(0, 2, (m, n))
norm_2 = np.array([[ sum((bi-uj)**2) for uj in U.T] for bi in B])
R = (norm_2 * Z).sum()
R
100566
# 优化失败.......
%timeit -n 30 (np.array([[ sum((bi-uj)**2) for uj in U.T] for bi in B]) * Z).sum()
69.1 ms ± 1.83 ms per loop (mean ± std. dev. of 7 runs, 30 loops each)
#练习5
##毫无头绪.....
A = np.array([3, 2, 1, 2, 3, 4, 6])
D = np.array([1, np.diff(A)])
np.cumsum(D)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-124-637022fda48d> in <module>()
----> 1 D = np.array([1, np.diff(A)])
2 np.cumsum(D)
ValueError: setting an array element with a sequence.
D = np.c_[[1,np.diff(A)]]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-122-7c4b91bd3712> in <module>()
----> 1 D = np.c_[[1,np.diff(A)]]
~\Miniconda3\envs\TF_2C\lib\site-packages\numpy\lib\index_tricks.py in __getitem__(self, key)
315 newobj = item
316 if ndmin > 1:
--> 317 tempobj = array(newobj, copy=False, subok=True)
318 newobj = array(newobj, copy=False, subok=True,
319 ndmin=ndmin)
ValueError: setting an array element with a sequence.
参考答案
#练习1
M1 = np.random.rand(2,3)
M2 = np.random.rand(3,4)
res = [[sum([M1[i][k] * M2[k][j] for k in range(M1.shape[1])]) for j in range(M2.shape[1])] for i in range(M1.shape[0])]
((M1@M2 - res) < 1e-15).all()
True
#练习2
A = np.arange(1,10).reshape(3,-1)
B = A*(1/A).sum(1).reshape(-1,1)
B
array([[ 1.83333333, 3.66666667, 5.5 ],
[ 2.46666667, 3.08333333, 3.7 ],
[ 2.65277778, 3.03174603, 3.41071429]])
#练习3
np.random.seed(0)
A = np.random.randint(10, 20, (8, 5))
B = A.sum(0)*A.sum(1).reshape(-1, 1)/A.sum()
res = ((A-B)**2/B).sum()
res
11.842696601945802
#练习4
#原方法
np.random.seed(0)
m, n, p = 100, 80, 50
B = np.random.randint(0, 2, (m, p))
U = np.random.randint(0, 2, (p, n))
Z = np.random.randint(0, 2, (m, n))
def solution(B=B, U=U, Z=Z):
L_res = []
for i in range(m):
for j in range(n):
norm_value = ((B[i]-U[:,j])**2).sum()
L_res.append(norm_value*Z[i][j])
return sum(L_res)
solution(B, U, Z)
100566
#改进方法 :
(((B**2).sum(1).reshape(-1,1) + (U**2).sum(0) - 2*B@U)*Z).sum()
100566
100566
# 性能对比
#原方法
%timeit -n 30 solution(B, U, Z)
54.1 ms ± 3 ms per loop (mean ± std. dev. of 7 runs, 30 loops each)
#改进方法
%timeit -n 30 ((np.ones((m,n))*(B**2).sum(1).reshape(-1,1) +\
np.ones((m,n))*(U**2).sum(0) - 2*B@U)*Z).sum()
332 µs ± 89.6 µs per loop (mean ± std. dev. of 7 runs, 30 loops each)
#自己方法
%timeit -n 30 (np.array([[ sum((bi-uj)**2) for uj in U.T] for bi in B]) * Z).sum()
75.9 ms ± 3.81 ms per loop (mean ± std. dev. of 7 runs, 30 loops each)
#练习5
f = lambda x:np.diff(np.nonzero(np.r_[1,np.diff(x)!=1,1])).max()
print(f([1,2,5,6,7]))
print(f([3,2,1,2,3,4,6]))
#1.
3
4
A = [1,2,5,6,7]
np.diff(A)
array([1, 3, 1, 1])
# 将连续的整数索引设置为0, 不连续的索引设置为1,目的是寻找连续串的边界情况.
np.diff(A)!= 1
array([False, True, False, False], dtype=bool)
# 将数组长度的区间边界和长度通过索引的方式存储.
np.r_[1, np.diff(A)!= 1,1]
array([1, 0, 1, 0, 0, 1], dtype=int32)
# 获取非零元素的索引,即获取连续区间边界索引,从而求取连续数组的长度
np.nonzero(np.r_[1,np.diff(A)!=1,1])
(array([0, 2, 5], dtype=int64),)
c = [1,2,3,4]
np.diff(c) != 1
array([False, False, False], dtype=bool)
np.nonzero(np.r_[1,np.diff(c)!=1,1])
(array([0, 4], dtype=int64),)