今天面试遇到几个问题,记录一下
今天面试时,遇到这么个问题: 给了一段代码:
A = [1, 2, 3, 4, 5]
B = []
for i in A:
B.append(i * i)
要求能否用效率更高的方式来写
一般这种情况,就直接祭出列表推导式了:
B = [i * i for i in A]
然后面试官又问,能否用别的方式,提示道可以用其他库
那我猜肯定是要考我numpy的用法和向量化了,也没多想,直接在纸上写:
import numpy as np
B = np.array(A).dot(np.array(A))
其实这时候已经错了,毕竟也很久没和矩阵打交道了,我忘记了点乘每一项之后是要加起来的( ╯□╰ )
这问题也是一直到上地铁才想到,两个1维向量,点乘应该是一个数才对
这种写法,B其实变成了一个数
B
55
面试官这时候分享了她想要的答案:
A = np.array(A)
B = A * A
B
array([ 1, 4, 9, 16, 25])
事实上,如果想用点乘来做,应该这么写:
A = [1, 2, 3, 4, 5]
A = np.array(A)
B = A.dot(A * np.identity(A.shape[0]))
B
array([ 1., 4., 9., 16., 25.])
其中 np.identity() 是单位矩阵
那 *, np.dot, array.dot之间到底什么关系,做个实验
X = np.array([
[1,2],
[3,4]
])
Y = np.array([
[5,6],
[7,8]
])
print(X * Y)
print('--------------')
print(X.dot(Y))
print('--------------')
print(Y.dot(X))
print('--------------')
print(np.dot(X, Y))
print('--------------')
print(np.dot(Y, X))
[[ 5 12]
[21 32]]
--------------
[[19 22]
[43 50]]
--------------
[[23 34]
[31 46]]
--------------
[[19 22]
[43 50]]
--------------
[[23 34]
[31 46]]
可以看出
* 是相同下标相乘, 如果一边是一个数,则整个矩阵乘那个数
X.dot(Y) 是 X 左乘 Y np.dot(X, Y) 是左边左乘右边
之后又问了个问题:
def func(A):
B = A * A
return B
A = np.array([1, 2, 3, 4, 5])
B = func(A)
C = B
# A,B,C内存地址的关系?
C和B指向同一个地址很明显:
id(B) == id(C)
True
关键是A和B,在这里我并不清楚A * A返回的到底是一个新的array对象还是在A的基础上修改的对象,所以这里只好老实回答不清楚
面试官这时候说A和BC一样指向的同一个地址,我先记下这个结论
回来打开notebook试一下:
id(A) == id(B)
False
竟然不一样? 我蒙蔽了
大概是因为对于np.array的乘法的理解偏差,这里做个实验:
A = np.array([[1,2,3,4,5]])
B = A * A
print(id(A))
print(id(B))
1533489663152
1533489660272
两个id并不一样
在这里应该是想考察函数里面改变了对象, 跟原来对象的关系, 但实际上乘号是不会影响原array的值的
如果把题目改成这样,那就可以达到想要的效果
def func(A):
A[3] = 100
B = A
return B
A = np.array([1, 2, 3, 4, 5])
B = func(A)
C = B
print(id(A) == id(B) == id(C))
A
True
array([ 1, 2, 3, 100, 5])