Datawhale开源学习内容的链接:https://datawhalechina.github.io/joyful-pandas/build/html/%E7%9B%AE%E5%BD%95/ch1.html
本次笔记是针对自己的情况,记录一些自己之前不会或不熟悉的内容,以及一些有启发的内容。
共分为两个板块,第一个板块是,纯粹的知识内容;第二个板块是练习题,记录自己的思路与习题答案。
一、知识整理
1、map函数的用法
map函数的原型是map(function, iterable, …),它的返回结果是一个列表。
参数function传的是一个函数名,可以是python内置的,也可以是自定义的。
参数iterable传的是一个可以迭代的对象,例如列表,元组,字符串这样的。
这个函数的意思就是将function应用于iterable的每一个元素,结果以列表的形式返回。iterable后面还有省略号,意思就是可以传很多个iterable,如果有额外的iterable参数,并行的从这些参数中取元素,并调用function。如果一个iterable参数比另外的iterable参数要短,将以None扩展该参数元素。还是看例子来理解吧!
2、列表推导式
可以把for循环的式子写得很简易,并且效率也会更高。
3、随机矩阵的应用
【这块之前自己没有这样理解,需在复习下概率,然后看看代码与数学的联系】
对于服从区间a到b上的均匀分布可以如下生成:
a, b = 5, 15
(b-a) * np.random.rand(3) + a
输出:array([11.89843468, 12.39037732, 12.97019338])
randn生成了N ( 0 , I ) N(0,I)N(0,I)的标准正态分布:
np.random.randn(3)
输出: array([-0.25552709, 2.2353 , -0.36139888])
np.random.randn(2,2)
输出:array([[-2.19975086, -0.88199378],
[ 1.04841871, 0.3310393 ]])
对于服从方差σ 2 \sigma^{2}σ2,均值为μ \muμ的一元正太分布可以如下生成:
sigma, mu = 2.5, 3
mu + np.random.randn(3) * sigma
输出:array([ 2.17315548, 0.72791185, -1.5962757 ])
4、分位数
参考连接:https://www.zhihu.com/question/67763556
二、练习
1、利用列表推导式写矩阵乘法
(先忽略给出的代码,首先用循环写出矩阵乘法,再转换为列表推导式)
思考步骤:
1、首先想一下矩阵乘法的方式。(两个矩阵的哪些元素相乘?)
2、思考一下有哪些循环,几层循环。(首先第一个矩阵是每次取一行的元素,所以要记录第一个矩阵的行数;然后第二个矩阵是每次取一列的元素,所以我们要记录第二个矩阵的列数,看看有多少列,就要取多少次;接着我们要将取出来的行元素与列元素对应相乘,那么就还需要一个循环来进行记录,并且这个循环封顶的值即为第一个矩阵的列数,同时也是第二个矩阵的行数)
3、先将矩阵乘法的普通的循环写出来。
M1 = np.random.rand(2,3)
M2 = np.random.rand(3,4)
res = np.empty((M1.shape[0],M2.shape[1]))
for i in range(M1.shape[0]):
for j in range(M2.shape[1]):
item = 0
for k in range(M1.shape[1]):
item += M1[i][k] * M2[k][j]
res[i][j] = item
在这里我自己发现了个问题,循环部分我最开始写的
for i in range(len(M1[0])):
for j in range(len(M2[1])):
temp = 0
value = 0
for k in range(len(M1[1])):
temp = M1[i][k] * M2[k][j]
value += temp
res[i][j] = value
导致报错:IndexError: index 2 is out of bounds for axis 0 with size 2
排查原因:
M1 = np.arange(6).reshape(2,3)
M2 = np.arange(12).reshape(3,4)
print(M1)
print(M1.shape)
print(M1.shape[0])
print("***",len(M1[0]))
print(M1[0][2])
print(len(M1[1]))
print(len(M2[0]))
print(len(M2[1]))
输出:
[[0 1 2]
[3 4 5]]
(2, 3)
2
*** 3
2
3
4
4
M.shape[0]是指的一个大小为(2, 4)矩阵的第一个维度2
然后len(M[0])却是指的第一行元素的个数,len(M[1])指的第二行元素的个数,然后这些都指的是列数,而不是行数!!学到了~之前都没太注意这个问题。
## 检查自己的结果是否正确
((M1@M2 - res) < 1e-15).all() # 排除数值误差
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])]
2、更新矩阵

自己的答案:
A = np.arange(1,10).reshape(3,-1)
for i in range(A.shape[0]):
raw_sum = 0
for j in range(A.shape[1]):
raw_sum += 1/A[i][j]
print(raw_sum)
for i in range(A.shape[0]):
for j in range(A.shape[1]):
B[i][j] = A[i][j] * raw_sum
print(B)
输出:
1.8333333333333333
0.6166666666666667
0.37896825396825395
[[0.37896825 0.75793651 1.13690476]
[1.51587302 1.89484127 2.27380952]
[2.65277778 3.03174603 3.41071429]]
参考答案:
A = np.arange(1,10).reshape(3,-1)
B = A*(1/A).sum(1).reshape(-1,1)
print(B)
输出:
[[1.83333333 3.66666667 5.5 ]
[2.46666667 3.08333333 3.7 ]
[2.65277778 3.03174603 3.41071429]]
发现木有!竟然只有最后一行答案正确!我往前看原因,原来是没有把每一行的倒数和存成列表,导致下面乘的和全是第三行的和。
修改后:
A = np.arange(1,10).reshape(3,-1)
add_sum = []
for i in range(A.shape[0]):
raw_sum = 0
for j in range(A.shape[1]):
raw_sum += 1/A[i][j]
print(raw_sum)
add_sum.append(raw_sum)
print(add_sum)
for i in range(A.shape[0]):
for j in range(A.shape[1]):
B[i][j] = A[i][j] * add_sum[i]
print(B)
总结:别人用一个内置函数就解决的问题,然而我用了两个循环做。。。还是要多写多用才可以!
3、卡方统计量

鉴于上一题,自己傻傻的用了循环来计算和,所以这次我也使用内置函数啦!现学先现用!
np.random.seed(0)
A = np.random.randint(10, 20, (8, 5))
print(A.sum(1)) ## 计算每一行的和
print(A.sum(0)) ## 计算每一列的和
print(A.sum(1).sum(0)) ## 计算所有数的和
print(A.sum()) ## 计算所有数的和
写了如下代码,却得到了报错,一看就是维度除了问题,不能广播。那我们首先想一下广播的条件,其中一点就是必须要是1维的才能广播。
问题出在了:
B = A.sum(0) * A.sum(1)

因为(8,)不能与(5,)直接相乘,应将其转化为2维的。正确写法:
B = A.sum(0) * A.sum(1).reshape(-1,1) / A.sum()
print(B)
res = ((A-B) ** 2 / B).sum()
print(res)
4、改进矩阵计算的性能

待理解后再补
5、连续整数的最大长度
思考过程:
1、首先我做了以下代码查看
a = [1,2,1,3,4,5,6,7,1]
np.diff(a)
输出:array([ 1, -1, 2, 1, 1, 1, 1, -6])
得到三个发现,一是,我们可以根据1来判断是否是连续整数;二是,当出现多个间断的1的时候,需要取数目更多的那个;三是,最大长度等于连续1的个数之和加1。
2、那么我需要做的是,首先判断是否为1,其次还要记录这个连续1的数量。
b = [2,4,5,6,7,1]
print(np.diff(b))
add_sum = 0
for i in range(len(b)-1):
if np.diff(b)[i] == 1:
add_sum += 1
max_num = add_sum + 1
else:
add_sum = 0
print(max_num)
输出: 4
遇到的问题:
最开始写的range(len(b)) 但是报了角标的错误,因为我忽略了做了diff之后,长度要比原始长度少1。并且这样
参考答案:
f = lambda x:np.diff(np.nonzero(np.r_[1,np.diff(x)!=1,1])).max()
f([2,4,5,6,7,1])
输出: 4