Pandas学习-Task01

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

版权声明:本文为hahameier原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。