问题描述
Python脚本 :我想将一个行/列以外的整个矩阵与标量相乘。 行/列号是一个变量。
例如,
[[2 2 2 2 2]
[2 2 2 2 2]]
num = 2
标量= 3
我希望结果看起来像这样
[[6 6 2 6 6]
[6 6 2 6 6]]
我不要任何循环。 我可以使用numpy或pandas。 实现此目标的最佳方法是什么?
1楼
In [52]: num, scalar = 2,3
一种使列倍增的方法:
In [53]: mul = np.ones(5,int)*scalar
In [54]: mul[num] = 1
In [55]: arr = np.ones((2,5),int)*2
In [56]: arr
Out[56]:
array([[2, 2, 2, 2, 2],
[2, 2, 2, 2, 2]])
In [57]: mul
Out[57]: array([3, 3, 1, 3, 3])
In [58]: arr * mul # (2,5) * (5,)
Out[58]:
array([[6, 6, 2, 6, 6],
[6, 6, 2, 6, 6]])
2楼
在连续块上运行非常快。 因此,可能最快的解决方案是:
temp = A[:, k].copy()
A *= x
A[:, k] = temp
一些时间。
上面的方法是i_pp_1
, f_pp_1
是相同的位置。
就地和就地解决方案分别列出。
就地定时会进行更正,以进行显式复制。
下面的行copy
也已进行复制纠正,即应设置为零,直到出现噪音为止:
size: (2, 5)
inplace
copy -0.0 us
i_pp_1 2.5 us
i_pp_2 6.3 us
i_hpaulj 3.7 us
i_jpp 17.0 us
new out
f_pp_1 1.4 us
f_hpaulj 3.6 us
size: (20, 50)
inplace
copy -0.0 us
i_pp_1 3.3 us
i_pp_2 9.0 us
i_hpaulj 5.1 us
i_jpp 21.0 us
new out
f_pp_1 2.1 us
f_hpaulj 5.1 us
size: (200, 500)
inplace
copy -0.1 us
i_pp_1 57.0 us
i_pp_2 207.7 us
i_hpaulj 103.2 us
i_jpp 773.8 us
new out
f_pp_1 67.6 us
f_hpaulj 116.8 us
码:
import numpy as np
from timeit import timeit
def copy():
B = A.copy()
return B
def i_pp_1():
B = A.copy()
keep = B[:, k].copy()
B *= x
B[:, k] = keep
return B
def i_pp_2():
B = A.copy()
B[:, :k] *= x
B[:, k+1:] *= x
return B
def f_pp_1():
B = x * A
B[:, k] = A[:, k]
return B
def f_hpaulj():
f = np.full(A.shape[1:], x)
f[k] = 1
B = A * f
return B
def i_hpaulj():
B = A.copy()
f = np.full(B.shape[1:], x)
f[k] = 1
B *= f
return B
def i_jpp():
B = A.copy()
B[:, np.delete(np.arange(B.shape[1]), k)] *= x
return B
for shp, sz in zip([(2, 5), (20, 50), (200, 500)], (1, 10, 100)):
A = np.random.randint(0, 10, shp)
k, x = 2, 3
print(f"size: {shp}")
offset = timeit(copy, number=1000000//sz)*sz
for kind, lst, off in [("inplace", (copy, i_pp_1, i_pp_2, i_jpp), offset),
("new out", (f_pp_1, f_hpaulj), 0)]:
print(kind)
for f in lst:
t = timeit(f, number=1000000//sz)*sz-off
print(f'{f.__name__:8s} {t:10.1f} us')
3楼
具有axis
参数,并且可以复制或执行(根据上述i_pp_1()
):
def exclusive_mult(a, num, scalar, axis = 0, inplace = True):
if not inplace:
a = a.copy()
s = tuple(slice(None, None, None) if i != axis else num for i in range(a.ndim))
keep = a[s].copy()
a *= scalar
a[s] = keep
if not inplace:
return a
测试:
a = np.full((2,5), 2)
exclusive_mult(a, 2, 3, 1)
a
Out:
array([[6, 6, 2, 6, 6],
[6, 6, 2, 6, 6]])
a = np.full((2,5), 2)
exclusive_mult(a, 2, 3, 1, False)
Out:
array([[6, 6, 2, 6, 6],
[6, 6, 2, 6, 6]])
a
Out:
array([[2, 2, 2, 2, 2],
[2, 2, 2, 2, 2]])
4楼
这是一种方法:
A = np.full((2, 5), 2)
num = 2
scalar = 3
A[:, np.delete(np.arange(A.shape[1]), num)] *= scalar
array([[6, 6, 2, 6, 6],
[6, 6, 2, 6, 6]])
5楼
这是另一种方式
a = np.array([[2, 2, 2, 2, 2], [2, 2, 2, 2, 2]])
num = 2
scalar = 3
b = tuple({i for i in range(a.shape[1]) if i != num})
a[:, b] *= scalar
编辑:我只是注意到您不希望任何循环和b初始化为一个。