函数格式tile(A,reps),A和reps都是array_like类型: 1. 参数A几乎所有类型都可以:array, list, tuple, dict, matrix这些序列化类型以及Python中基本数据类型int,float,string,bool类型。 2. 参数reps可以是tuple,list, dict, array, int, bool。但不可以是float, string, matrix(多维度的ndarray数组)类型。
tile函数的功能是重复某个数组。比如tile(A, reps),它的作用就是把A重复reps次,这也可以理解为什么参数reps不能是float、string以及matrix类型 ,对于参数reps不能为float和string类型很好理解,这里不再赘述,后面将介绍为什么参数reps不能是matrix类型。
其实如果可以使用Python广播机制的话是没有必要使用tile函数的。下面就来通过源码来简单分析tile函数的运作,以及如何简单的使用它。
a
tile 源码分析
这里通过tile函数的源码来分析tile函数,为什么能实现复制的功能。
def tile(A, reps):
try:
tup = tuple(reps)
except TypeError:
tup = (reps,)
d = len(tup)
if all(x == 1 for x in tup) and isinstance(A, _nx.ndarray):
# Fixes the problem that the function does not make a copy if A is a
# numpy array and the repetitions are 1 in all dimensions
return _nx.array(A, copy=True, subok=True, ndmin=d)
else:
# Note that no copy of zero-sized arrays is made. However since they
# have no data there is no risk of an inadvertent overwrite.
c = _nx.array(A, copy=False, subok=True, ndmin=d)
if (d < c.ndim):
tup = (1,)*(c.ndim-d) + tup
shape_out = tuple(s*t for s, t in zip(c.shape, tup))
n = c.size
if n > 0:
for dim_in, nrep in zip(c.shape, tup):
if nrep != 1:
c = c.reshape(-1, n).repeat(nrep, 0)
n //= dim_in
return c.reshape(shape_out)
#定义了函数体的名称tile
#参数:
#------A:进行操作的对象
#------reps:重复的次数
def tile(A, reps):
try:
tup = tuple(reps)
except TypeError:
tup = (reps,)
这个地方很好理解,它是把传进来的reps通过tuple函数转换成Python元组。下面我们一个个类型来看。
import numpy as np
print("list to tuple:",tuple([1,2]))
print("dict to tuple:",tuple({'A':1,'B':2}))
print("ndarray to tuple:",tuple(np.array([1,2])))
# print("int to tuple:",tuple(1))#error抛出TypeError异常执行tup = (reps,)
# print("bool to tuple:",tuple(True))##error抛出TypeError异常执行tup = (reps,)
#不可以作为reps参数的类型
# print("float to tuple:",tuple(1.2))#error抛出TypeError异常执行tup = (reps,)
print("string to tuple:",tuple('12'))
print("matrix to tuple:",tuple(np.array([[1,2],[3,4]])))
▲result
可以看出前面介绍的不可以作为参数reps类型在这里可以安全的执行通过,所以这个地方并不是限制参数reps类型的根源所在。
▲reps可以为的参数类型
▲reps不可以为的参数类型
其实使用tuple函数转换成元组失败是因为tuple函数它需要的是一个可迭代的参数类型,如果不是的话就会抛出Typeerror的异常,抛出异常在源码中就会把值直接放入元组的第一个位置,这里的(reps,)也是一个元组类型。其实抛出异常对应的无非就是一些标量值,像int,True以及不能作为参数的float类型。
#这个其实很好理解
#要注意len((reps,))就是reps的元素个数
d = len(tup)
print(len((True,)))#1
对应上面的分析,这里无非也就是两种情况:
if all(x == 1 for x in tup) and isinstance(A, _nx.ndarray):
# Fixes the problem that the function does not make a copy if A is a
# numpy array and the repetitions are 1 in all dimensions
return _nx.array(A, copy=True, subok=True, ndmin=d)
else:
# Note that no copy of zero-sized arrays is made. However since they
# have no data there is no risk of an inadvertent overwrite.
c = _nx.array(A, copy=False, subok=True, ndmin=d)
这里有几个函数需要注意:
#可以把这个先看成是import numpy as np
import numpy.core.numeric as _nx
print(_nx.ndarray)
#从输出可以看出,isinstance(A, _nx.ndarray)判断A是不是ndarray类型的数据
'''
<class 'numpy.ndarray'>
'''
这里的all(x == 1 for x in tup)就是为什么参数reps不能使用matrix类型的根源所在。
import numpy as np
reps = np.array([[1,2],[3,4]])
print(all((x == 1 for x in reps)))
'''
Traceback (most recent call last):
File "G:/Python源码/numpy_test/numpy_test.py", line 1763, in <module>
print(all((x == 1 for x in reps)))
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
'''
然后我们来分析这个判断语句把那些情况筛选出去了:
if (d < c.ndim):
tup = (1,)*(c.ndim-d) + tup
这是什么样的情况呢?因为c.ndim也就是c的维度与d也就是元组中的元素个数不匹配,或者说是要进行重复的A的维度和reps重复次数不匹配,这样可想而知是不可以的,所以加入了一个进行处理的代码。
import numpy as np
import numpy.core.numeric as _nx
A = np.array([[1,2],[3,4]])
tup = (2,)
d = len(tup)
c = _nx.array(A, copy=False, subok=True, ndmin=d)
if (d < c.ndim):
tup = (1,)*(c.ndim-d) + tup
print(d)#1
print(c.ndim)#2
print(tup)#(1, 2)
▲result
shape_out = tuple(s*t for s, t in zip(c.shape, tup))
因为我们在第五步的时候,已经将我们的c的ndim与我们的tup的维度匹配。我们把shape属性和我们需要进行重复次数的tup中对应的元素相乘形成新的数组,这个结果作为我们最终的shape。
n = c.size
if n > 0:
for dim_in, nrep in zip(c.shape, tup):
#nrep == 1就不需要进行复制了
if nrep != 1:
c = c.reshape(-1, n).repeat(nrep, 0)
n //= dim_in
第六步实现了对最终输出结果的shape的形成。之后就是很重要的如何去进行复制呢?这里的c.size得到的结果是c中元素的个数:
for dim_in, nrep in zip(c.shape, tup):
#nrep == 1就不需要进行复制了
if nrep != 1:
c = c.reshape(-1, n).repeat(nrep, 0)
n //= dim_in
从上面的分析我们也可以知道,到这一步,我们的shape和tup中的元素个数是相互匹配的。
return c.reshape(shape_out)
b
示例代码
分析完了代码,看看怎么去使用。
从源码的分析上看:
import numpy as np
A = np.array([1,2])
reps = (1,1)
print(np.tile(A,reps))
'''[[1 2]]'''
从源码的分析上看:
import numpy as np
A = np.array([[1,2],[3,4]])
reps = (1,2)
print(np.tile(A,reps))
'''
[[1 2 1 2]
[3 4 3 4]]
'''