numpy 배열에서 곱하기


87

2D 배열의 각 항에 1D 배열의 해당 항을 곱하려고합니다. numpy.multiply 함수에 표시된 것처럼 모든 열에 1D 배열을 곱하려는 경우 매우 쉽습니다 . 그러나 저는 반대로 행의 각 항을 곱하고 싶습니다. 즉, 곱하고 싶습니다.

[1,2,3]   [0]
[4,5,6] * [1]
[7,8,9]   [2]

그리고 얻다

[0,0,0]
[4,5,6]
[14,16,18]

그러나 대신 나는

[0,2,6]
[0,5,12]
[0,8,18]

numpy로 우아한 방법이 있는지 아는 사람이 있습니까? 고마워, Alex


3
아, 질문을하자마자 알아 냈어요. 먼저 정사각형 행렬을 전치하고 곱한 다음 답을 전치하십시오.
Alex S

행을 열 행렬로 전치하는 것이 더 좋습니다. 그러면 답을 다시 전치 할 필요가 없습니다. 새 축 ( ) 을 추가하여 전치 A * B해야하는 경우 . A * B[...,None]BNone
askewchan 2013-08-30

감사합니다. 사실입니다. 문제는 .transpose () 또는 .T를 호출하는 1D 배열이있을 때 열 배열로 변환하지 않고 행으로 남겨 두는 한 열로 정의해야한다는 것입니다. 방망이에서 바로. 좋아요 x = [[1],[2],[3]]또는 뭔가.
Alex S

답변:


114

당신이 보여준 것과 같은 정상적인 곱셈 :

>>> import numpy as np
>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> c = np.array([0,1,2])
>>> m * c
array([[ 0,  2,  6],
       [ 0,  5, 12],
       [ 0,  8, 18]])

축을 추가하면 원하는 방식으로 곱해집니다.

>>> m * c[:, np.newaxis]
array([[ 0,  0,  0],
       [ 4,  5,  6],
       [14, 16, 18]])

두 번 전치 할 수도 있습니다.

>>> (m.T * c).T
array([[ 0,  0,  0],
       [ 4,  5,  6],
       [14, 16, 18]])

새로운 축 방법을 사용하면 2 개의 1D 배열을 곱하고 2D 배열을 생성 할 수 있습니다. 예 [a,b] op [c,d] -> [[a*c, b*c], [a*d, b*d]].
KON 정신

47

속도에 대한 여러 옵션을 비교 한 결과 놀랍게도 모든 옵션 (제외 diag)이 똑같이 빠릅니다. 나는 개인적으로

A * b[:, None]

(또는 (A.T * b).T) 짧기 때문입니다.

여기에 이미지 설명 입력


플롯을 재현하는 코드 :

import numpy
import perfplot


def newaxis(data):
    A, b = data
    return A * b[:, numpy.newaxis]


def none(data):
    A, b = data
    return A * b[:, None]


def double_transpose(data):
    A, b = data
    return (A.T * b).T


def double_transpose_contiguous(data):
    A, b = data
    return numpy.ascontiguousarray((A.T * b).T)


def diag_dot(data):
    A, b = data
    return numpy.dot(numpy.diag(b), A)


def einsum(data):
    A, b = data
    return numpy.einsum("ij,i->ij", A, b)


perfplot.save(
    "p.png",
    setup=lambda n: (numpy.random.rand(n, n), numpy.random.rand(n)),
    kernels=[
        newaxis,
        none,
        double_transpose,
        double_transpose_contiguous,
        diag_dot,
        einsum,
    ],
    n_range=[2 ** k for k in range(14)],
    logx=True,
    logy=True,
    xlabel="len(A), len(b)",
)

2
줄거리에 대한 코드를 제공하는 멋진 터치. 감사.
rocksNwaves

17

행렬 곱셈 (내적이라고도 함)을 사용할 수도 있습니다.

a = [[1,2,3],[4,5,6],[7,8,9]]
b = [0,1,2]
c = numpy.diag(b)

numpy.dot(c,a)

더 우아한 것은 아마도 취향의 문제 일 것입니다.


2
좋은, 하나는, 그 생각하지 않았다
jterrace

10
dot여기 정말 과잉입니다. 당신은 0과 추가 0으로 불필요한 곱셈을하고있는
바이 리코

2
nx1 벡터를 d가 n보다 큰 nxd 행렬에 곱하려는 경우에도 메모리 문제가 발생할 수 있습니다.
Jonasson

이 같은 Downvoting 느리고 밀도를 만들 때 메모리를 많이 사용하는 diag행렬.
Nico Schlömer

16

또 다른 트릭 (v1.6 기준)

A=np.arange(1,10).reshape(3,3)
b=np.arange(3)

np.einsum('ij,i->ij',A,b)

나는 numpy 방송 ( newaxis)에 능숙 하지만 여전히이 새로운 einsum도구에 대한 방법을 찾고 있습니다. 그래서 나는이 해결책을 찾기 위해 조금 놀았습니다.

타이밍 (Ipython timeit 사용) :

einsum: 4.9 micro
transpose: 8.1 micro
newaxis: 8.35 micro
dot-diag: 10.5 micro

부수적으로하는 변화 ij, np.einsum('ij,j->ij',A,b)알렉스 원하지 않는 행렬을 생성합니다. 그리고 np.einsum('ji,j->ji',A,b)사실상 이중 조옮김을합니다.


1
적어도 몇 밀리 초가 걸릴만큼 충분히 큰 어레이가있는 컴퓨터에서이 시간을 측정하고 관련 시스템 정보와 함께 여기 에 결과를 게시하면 많은 도움이 될 것입니다.
다니엘

1
더 큰 배열 (100x100)에서는 상대적인 숫자가 거의 같습니다. einsumm(25 마이크로)는 다른 것보다 두 배 빠릅니다 (점 진단은 더 느려짐). 이것은 'libatlas3gf-sse2'및 'libatlas-base-dev'(Ubuntu 10.4, 단일 프로세서)로 새로 컴파일 된 np 1.7입니다. timeit10000 루프의 최고를 제공합니다.
hpaulj

1
이것은 훌륭한 대답이며 받아 들여졌어야 할 대답이라고 생각합니다. 그러나 위에 작성된 코드는 실제로 Alex가 피 하려던 매트릭스를 제공합니다 (내 컴퓨터에서). hpaulj가 틀렸다고 말한 것은 실제로 옳은 것입니다.
Yair Daon

여기에서 타이밍이 잘못되었습니다. dot-diag는 실제로 다른 세 가지 옵션보다 훨씬 나쁘고 einsum은 다른 옵션보다 빠르지 않습니다.
Nico Schlömer

@ NicoSchlömer, 내 대답은 거의 5 년 전이며 많은 numpy버전이 돌아 왔습니다.
hpaulj

1

Google에서 잃어버린 영혼을 위해 numpy.expand_dimsthen numpy.repeat을 사용 하면 효과가 있으며 더 높은 차원의 경우에서도 사용할 수 있습니다 (예 : 모양 (10, 12, 3)에 a (10, 12)를 곱함).

>>> import numpy
>>> a = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
>>> b = numpy.array([0,1,2])
>>> b0 = numpy.expand_dims(b, axis = 0)
>>> b0 = numpy.repeat(b0, a.shape[0], axis = 0)
>>> b1 = numpy.expand_dims(b, axis = 1)
>>> b1 = numpy.repeat(b1, a.shape[1], axis = 1)
>>> a*b0
array([[ 0,  2,  6],
   [ 0,  5, 12],
   [ 0,  8, 18]])
>>> a*b1
array([[ 0,  0,  0],
   [ 4,  5,  6],
   [14, 16, 18]])

-4

그냥하지 그래

>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> c = np.array([0,1,2])
>>> (m.T * c).T

??


6
그 정확한 접근 방식은 이미 받아 들여진 답변에 나와 있지만 이것이 어떻게 추가되는지는 알 수 없습니다.
Baum mit Augen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.