当前位置: 代码迷 >> python >> 在python中将除一行/列之外的整个矩阵相乘
  详细解决方案

在python中将除一行/列之外的整个矩阵相乘

热度:45   发布时间:2023-07-16 10:11:57.0

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。 实现此目标的最佳方法是什么?

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]])

在连续块上运行非常快。 因此,可能最快的解决方案是:

temp = A[:, k].copy()
A *= x
A[:, k] = temp

一些时间。 上面的方法是i_pp_1f_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')

具有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]])

这是一种方法:

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]])

这是另一种方式

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初始化为一个。