文章目录
Pandas数据分析-Task1
记录DataWhale的Pandas数据分析的学习过程,使用的教材为 joyful-pandas。
Task1包含Python与numpy的复习,Python包含列表推导式,匿名函数,zip函数;Nump介绍了一些基本操作;最后是5道练习题。本人完全小白一个,如果有错误希望大家能指正一下。
Python基础复习
列表推导式
1.列表推导式目的:快速生成新的列表,简化程序。
2.列表推导式格式:
[表达式1 for循环语句 0个或多个if或for语句]
列表推导式的执行顺序为先执行[]号内左侧第一个for循环语句,然后嵌套的执行其后的if语句或for语句,在嵌套的最后执行[]号内最左侧的表达式1。有以下语句1:
#语句1
l=[x+y for x in [1,2,3] for y in [3,1,4] if x != y]
print(l)
>输出为[4, 5, 5, 3, 6, 4, 7]
根据列表表达式的执行规则,其等同于语句2。
#语句2
l = []
for x in [1,2,3]:
for y in [3,1,4]:
if x != y:
l.append(x+y)
列表表达式1除了可以是简单的公式,还可以是函数。语句1就可以等效为以下的语句3。
#语句3
def f(x,y)
return x+y
l=[f(x,y) for x in [1,2,3] for y in [3,1,4] if x != y]
print(l)
3.语法糖
value = x if condition else y
此语法糖可以用一个语句实现单分支结构,我们可以把这个语法糖结合到列表推导式中,在语句3的基础上变换,有:
#语句4
l=[f(x,y) if x != y else 0 for x in [1,2,3] for y in [3,1,4] ]
>输出为[4, 0, 5, 5, 3, 6, 0, 4, 7]
map函数
1.作用:根据指定函数对指定序列做映射。
2.用法:
map(函数名, 函数对应的实参序列)
map()函数是python的内置函数,返回的是map对象。上一节说到可以利用列表推导式简单的生成列表,在这里我们同样可以利用map()函数的映射性质生成列表。注意:map()函数返回的是map对象,需要使用list()函数将map对象转化为列表。
3.结合匿名函数:map()函数还可以使用lambda匿名函数做映射,以下是一个例子:
l=list(map(lambda x,y:x+y,range(5),range(5)))
#输出为[0, 2, 4, 6, 8]
zip函数
1.作用:打包多个可迭代对象,可以打包字符串,列表,元组,字典,集合,通常在for循环时使用zip函数。zip函数返回一个元组的迭代器,其中的第 i 个元组包含来自每个可迭代对象的第 i 个元素。这样说有些拗口,下面例子可以帮助理解
2.例子:
x=[1,2,3]
y=[4,5,6]
zipped=zip(x,y)
list(zipped) #zipped为zip对象,通过list()函数转化为列表显示
>>OutPut:[(1, 4), (2, 5), (3, 6)]
打包后的zipped变量第一个元素(1,4)分别来自列表x的第一个元素1和列表y的第一个元素4。
Numpy复习
numpy复习这一章主要介绍了numpy常用的一些方法与函数,这里主要介绍一些我个人掌握不好的方法。
1 np.random.choice()函数
作用:官方文档上说的是“Generates a random sample from a given 1-D array”,大体意思是从给定的一维数组中产生随机样本,超过一维的数组是不能输入choice函数的。
用法:choice(arrayA, size=None, replace=True, p=None). 其中,size可以为一个整数或者一个由整数构成的元组,代表choice函数输出的结构;replace参数用来选择有放回和无放回抽样;p参数是一个1-D array,是可选的参数,如果要赋值的话,长度必须和arrayA参数的长度一致,而且所有元素的和必须为1,因为p参数代表的是arrayA中每一个元素被选中的概率。
例子
myarray=np.array(['a', 'b', 'c', 'd'])
np.random.choice(my_list, 2, replace=False, p=[0.1, 0.7, 0.1 ,0.1])
>输出:['a' 'b']
2 np.reshape()与np.resize()的区别
np.reshape()与np.resize()作用都是一样的,区别在于np.resize()会直接在原数组上做修改,而np.reshape是生成一个修改后的副本。我在做实验的时候使用 np.arange(10).resize((2,5))这种写法,输出的不是新数组,而是None。而使用np.arange(10).reshape((2,5))就能产生正确的输出。不太清楚其中具体的原理,希望有同学能帮忙解释一下。
3 numpy.r_[]与numpy.c_[]
np.r_[]和numpy.c_[]都是拼接数组的,但他们不是函数,没有输入和输出,只是一个操作,所以不用(),而是用索引[]符号。简单来说,在二维数组上,np.r_[]操作可以表示为上下合并(r代表的就是row,显然是在数组的行方向进行合并),np.c_[]操作可以表示为左右合并(c代表的就是column)例如
x=np.arange(4).reshape((2,2))
np.r_[x,x]
>输出为:
>[[0 1]
[2 3]
[0 1]
[2 3]]
np.c_[x,x]
>输出为:
>[[0 1 0 1]
[2 3 2 3]]
np.r_[]和np.c_[]的更一般的用法其实还挺复杂,官方文档上给的解释没有太理解。。。
4 numpy.ix_()函数
np.ix_()是一个函数,可以快速构建索引数组,比如
a=np.arange(6).reshape((2,3))
>结果为:
>[[0 1 2]
[3 4 5]]
a[np.ix_([0,1],[1,2])]
>结果为:
>[[1 2]
[4 5]]
可以很明显的看出,x[np.ix_([0,1],[1,2])] 就是
[ [a[0,1] a[0,2]], [a[1,1] a[1,2]] ], 所以,np.ix_([0,1],[1,2)]
相当于在[0,1]和[1,2]这两个序列之间做了笛卡尔乘积,再把笛卡尔乘积后的结果作为索引。
5 nan*统计函数
numpy中像max,min,mean等这些统计函数,无法处理有缺失值的数组,以前遇到这种问题都是自己先把缺失值去掉再统计,十分麻烦。不知道还有nan*这种函数,nanmax,nanmin,nanmin等就可以直接忽略缺失值进行计算,很方便。
6 广播
numpy数组中的加减乘除各种运算都是element-wise的,即元素对应位置进行数值运算,当两个数组维度不一致时,是不能直接进行运算的,但是有一些特殊情况,这些特殊情况就称之为广播运算。joyful-pandas教材中已经介绍了两维以内的广播机制,这里再补充一个,数组x(m,1)与数组y(1,n)之间也可以进行广播运算,例如:
x=np.arange(3).reshape(-1,1) #3*1
>[[0]
[1]
[2]]
y=np.arange(4).reshape(1,-1) #1*4
>[[0 1 2 3]]
print(x*y) #3*4
>[[0 0 0 0]
[0 1 2 3]
[0 2 4 6]]
可以看出,把原来为 3 ∗ 1 3*1 3∗1的数组X扩充为3*4的数组:
[[0 0 0 0]
[1 1 1 1]
[2 2 2 2]]
同样把原来为 1 ∗ 4 1*4 1∗4的数组X扩充为3*4的数组:
[[0 1 2 3]
[0 1 2 3]
[0 1 2 3]]
然后两个扩充后的数组再对应元素相乘即可得到结果。
7 numpy.sum()函数
np.sum()函数在作业中出现了好几次,这里也介绍一下。np.sum()函数的作用,官方文档说的是“Sum of array elements over a given axis”,所以要会使用np.sum()函数,就一定先理解numpy中的axis的意义。
如下图的二维数组所示,二维数组有两个轴,axis0与axis1。从图中也可以看出,axis0轴跨越了数组中的行,也即,axis0轴是纵轴,跨越行向下延伸。同样,我们也可以看出,axis1轴是横轴,跨越列向右延伸。
知道了轴的基本定义,就能理解np.sum(axis=None)函数了,假设A(m,n)是一个二维数组,A.sum(0)函数求的就是A数组axis0轴方向上的和,相当于将A的第一列所有元素求和,第二列所有元素求和…第n列所有元素求和,所以最后的输出为长度为n的一维数组。同理,A.sum(1)函数的算的是A数组m行中每行的所有元素之和,最后输出的是长度为m的一维数组。
练习
练习1:利用列表推导式写矩阵乘法
我的解答:
def f(i,j):
item=0
for k in range(M1.shape[1]):
item += M1[i][k] * M2[k][j]
return item
res=[[f(i,j) for j in range(M2.shape[1])] for i in range(M1.shape[0])]
print(((M1@M2 - res) < 1e-15).all())
>True
参考答案:
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])]
print(((M1@M2 - res) < 1e-15).all())
>True
分析:因为要生成的列表是二维的,考虑到了嵌套使用列表推导式,但是第三个for循环不知道怎么添加到列表推导式中,看了参考答案后才知道python自带的sum()函数中也可以使用for循环,这样就可以把第三个for循环嵌套进列表表达式了。果然我这样零基础的菜鸡需要学习的东西还有很多。
练习2:更新矩阵
这一道题比较简单,和参考答案的思路是一样的,先用(1/A).sum(axis=0)求出来
1
/
A
1/A
1/A每一列的和,再reshape一下,最后和A数组通过广播运算就能得到结果。
A=np.arange(1,10).reshape(3,3)
print(A*((1/A).sum(axis=0).reshape(-1,1)))
练习3:卡方统计
这道题需要先构造
B
B
B矩阵,我用的方法是通过A.sum(0)与A.sum(1)进行矩阵乘法运算,参考答案用的是一维数组与二维数组之间的广播。
我的解答:
B=(A.sum(axis=1).reshape((-1,1)) @ A.sum(axis=0).reshape((1,-1)))/A.sum()
result=((A-B)**2/B).sum()
参考答案:
B=A.sum(0)*(A.sum(1).reshape(-1,1))/A.sum()
result=((A-B)**2/B).sum()
练习4:改进矩阵计算的性能
这道题没有做出来(菜鸡被打回原形。。。),这道题参考答案用的是一个很简单的数学公式:
(
b
−
u
)
2
=
b
2
+
u
2
−
2
b
u
(b-u)^2=b^2+u^2-2bu
(b−u)2=b2+u2−2bu。具体做法是先利用np.sum()求出
B
i
2
B_i^2
Bi2和
U
j
2
U_j^2
Uj2,然后利用广播将其扩展为m*n的二维数组,最后减去
B
U
BU
BU即可。
参考答案:
t1=np.ones((m,n))*(B.sum(axis=1).reshape(-1,1))
t2=np.ones((m,n))*(U.sum(axis=0))
((t1+t2-2*B@U)*Z).sum()
练习5:连续整数的最大长度
这道题比较简单,思路和参考答案基本一致,我用的是np.append()拼接,答案用的是np.r_[],参考答案更简洁。
我的解答:
x=np.array([3,2,1,2,3,4,6])
print(np.diff(np.append(np.nonzero(np.diff(x)-1),len(x)-1)).max())
参考答案:
x=np.array([3,2,1,2,3,4,6])
f = lambda x:np.diff(np.nonzero(np.r_[1,np.diff(x)!=1,1])).max()
print(f(x))