Reference

NumPy

  • Numerical Python

Import

import numpy as np

Array Creation(ndarray)

  • N Dimensional Array
A = np.array([1,2,3])
A
array([1, 2, 3])
mylist = [3, 4, 5]
array_from_list = np.array(mylist)
array_from_list
array([3, 4, 5])
mytuple = (4,5,6)
array_from_tuple = np.array(mytuple)
array_from_tuple
array([4, 5, 6])
np.array(range(10))
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.linspace(0,1,12) # 0 ~ 1을 12등분하여 만듬 (끝점을 포함)
array([0.        , 0.09090909, 0.18181818, 0.27272727, 0.36363636,
       0.45454545, 0.54545455, 0.63636364, 0.72727273, 0.81818182,
       0.90909091, 1.        ])
len(np.linspace(0,1,12))
12
np.arange(5)
array([0, 1, 2, 3, 4])
np.arange(1,6)
array([1, 2, 3, 4, 5])
np.zeros(3) # 0을 3개
array([0., 0., 0.])
np.zeros((3,3))
array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])
np.ones(3) # 1을 3개
array([1., 1., 1.])
np.ones((3,3))
array([[1., 1., 1.],
       [1., 1., 1.],
       [1., 1., 1.]])
np.eye(3) # 단위 행렬
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
np.diag([1,2,3]) # 대각선이 1,2,3인 행렬
array([[1, 0, 0],
       [0, 2, 0],
       [0, 0, 3]])

Broadcasting

A+1 # 덧셈
array([2, 3, 4])
A-4 # 뺄셈
array([-3, -2, -1])
A*2 # 곱셈
array([2, 4, 6])
A/2 # 나눗셈
array([0.5, 1. , 1.5])
A**2 # 제곱
array([1, 4, 9])
A%2 # 나머지
array([1, 0, 1], dtype=int32)
np.sqrt(A)
array([1.        , 1.41421356, 1.73205081])
np.log(A)
array([0.        , 0.69314718, 1.09861229])
np.exp(A)
array([ 2.71828183,  7.3890561 , 20.08553692])
np.sin(A)
array([0.84147098, 0.90929743, 0.14112001])
A = np.array([11,22,33,44,55,66])

Indexing

A[2]
33
A[5]
66
A[1:4]
array([22, 33, 44])
A[[0,2,4]]
array([11, 33, 55])
A[[True, False, True, False, False, True]]
array([11, 33, 66])
A < 33
array([ True,  True, False, False, False, False])
A[A<33]
array([11, 22])

Matrix Indexing

A2 = np.array([[1,2,3,4],[-1,-2,-3,-4],[5,6,7,8],[-5,-6,-7,-8]])
A2
array([[ 1,  2,  3,  4],
       [-1, -2, -3, -4],
       [ 5,  6,  7,  8],
       [-5, -6, -7, -8]])
A2[1][3]
-4
A2[1,3]
-4
A2[0, 0:2]
array([1, 2])
A2[0]
array([1, 2, 3, 4])
A2[0, 2:]
array([3, 4])
A2[:, :]
array([[ 1,  2,  3,  4],
       [-1, -2, -3, -4],
       [ 5,  6,  7,  8],
       [-5, -6, -7, -8]])
A2[[0,2], :]
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])
A2[[0,2]]
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])

Useful Functions

np.random

{python}
np.random.

np.random.rand

{python}
np.random.rand(N)
np.random.rand(10) # 0~1 사이에서 10개의 난수 생성
array([0.74265347, 0.12865142, 0.9512475 , 0.24358922, 0.03553823,
       0.2295192 , 0.12775839, 0.0919773 , 0.50947895, 0.74584544])
np.random.rand(10)*2 # (0~1)*2 = 0~2 사이에서 10개의 난수 생성
array([0.70426213, 1.54703597, 0.73553232, 1.35319966, 1.7224698 ,
       1.43787541, 1.62631319, 1.54416732, 0.3511027 , 1.63909984])
np.random.rand(10)+1 # 1~2 사이에서 10개의 난수 생성
array([1.8882947 , 1.21487037, 1.87248472, 1.8506064 , 1.42443757,
       1.795348  , 1.37847909, 1.24870616, 1.66128972, 1.7608405 ])
np.random.rand(10)*2+1 # 1~3 사이에서 10개의 난수 생성
array([2.16303879, 1.27818637, 1.32514334, 1.6161346 , 2.03926784,
       1.50032755, 1.16183896, 1.51923212, 2.67152899, 1.2616228 ])

np.random.randn

{python}
np.random.randn(N)
np.random.randn(10) # 표준정규분포에서 10개 추출
array([ 0.16284596, -1.41505923, -0.87931282, -1.96742692, -0.17715718,
       -0.18035526,  1.31177136, -1.02100905, -0.3559429 ,  0.40319735])
np.random.randn(10)*2 # 평균이 0이고 표준편차가 2인 정규분포
array([ 0.29806358,  2.00020956, -0.5111455 , -3.0789904 ,  2.98176489,
        3.77815177, -1.25610359, -1.54689973, -2.11675118,  0.5415075 ])
np.random.randn(10)*2 + 3 # 평균이 0이고 표준편차가 3인 정규분포
array([ 0.19911518,  2.68233421,  3.80413328,  2.60169535,  2.48309103,
        5.28444139,  5.77762188,  5.52430879, -0.17405269,  3.34573411])

np.random.randint

  • 중복을 허용하지 않고 정수를 생성한다.
np.random.randint(7) # [0,7)의 범위에서 정수 한 개 생성
1
np.random.randint(7, size = (20,)) 
array([1, 0, 2, 1, 4, 4, 0, 2, 3, 1, 3, 5, 2, 5, 6, 5, 6, 1, 1, 2])
np.random.randint(7, size = (2,2)) # [0,7)의 범위 무작위 정수가 원소인 2x2 행렬을 생성한다.
array([[2, 1],
       [4, 6]])
np.random.randint(low=10, high=20, size=(2,5)) # [10, 20)의 범위에서 정수 한 개 생성
array([[16, 14, 13, 13, 11],
       [12, 11, 18, 14, 15]])

Warning :np.random.randint(high = N)은 사용할 수 없다.

np.random.choice

  • 복원추출이 default
np.random.choice(5,20)
array([3, 2, 4, 2, 0, 1, 1, 2, 1, 4, 3, 3, 3, 1, 0, 0, 0, 0, 2, 2])
np.random.choice(['apple', 'orange', 'banana'], 20)
array(['banana', 'apple', 'apple', 'apple', 'apple', 'banana', 'apple',
       'banana', 'banana', 'banana', 'orange', 'orange', 'apple', 'apple',
       'orange', 'orange', 'orange', 'orange', 'apple', 'banana'],
      dtype='<U6')
np.random.choice(5, 2, replace = False) # Replace = False로 하면 비복원추출을 시행한다.
array([2, 3])

np.random.binomial

np.random.binomial(n=10, p=0.2, size = (5,))
array([2, 3, 3, 2, 2])

np.random.normal

{python}
np.random.normal(loc = mean, scale = stdev, size)
default : np.random.normal(loc = 0, scale = 1, size = None)
np.random.normal(2, 3, 10) # 평균이 2이고 표준편차가 3인 정규분포
array([-2.2383093 ,  4.8091005 ,  0.15352256,  4.9793976 ,  0.33729707,
        6.12970338,  5.18818041, -1.62767898, -1.60791145,  0.97458435])

np.random.uniform

np.random.uniform(low=2, high=4, size = (5,)) # 균등분포
array([2.51568342, 2.3858703 , 2.42784566, 3.65082018, 2.5756164 ])
np.random.poisson(lam=5, size=(5,))
array([2, 5, 4, 3, 3])

np.random.poisson

np.random.poisson(lam=5, size=(5,))
array([3, 7, 3, 4, 4])

.corrcoef

np.random.seed(43052) 
x= np.random.randn(10000)
y= np.random.randn(10000)*2
z= np.random.randn(10000)*0.5 

np.corrcoef([x,y,z]).round(2)
array([[ 1.  , -0.01,  0.01],
       [-0.01,  1.  ,  0.  ],
       [ 0.01,  0.  ,  1.  ]])

.cov

np.cov([x,y,z]).round(2)
array([[ 0.99, -0.02,  0.  ],
       [-0.02,  4.06,  0.  ],
       [ 0.  ,  0.  ,  0.25]])

.reshape

Tip: R의 dim 함수와 유사하다.
A = np.array([11,22,33,44,55,66])
A
array([11, 22, 33, 44, 55, 66])
A.reshape(2,3)
array([[11, 22, 33],
       [44, 55, 66]])
A
array([11, 22, 33, 44, 55, 66])
A = A.reshape(2,3)
A
array([[11, 22, 33],
       [44, 55, 66]])

note :reshape with -1

A = np.arange(24)
A
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23])
A.reshape(2,-1) # 행의 수가 2인 행렬, 열은 알아서 맞춰
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]])
A.reshape(4, -1) # 행의 수가 4인 행렬, 열은 알아서 맞춰
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23]])
A.reshape(-1, 4) # 열의 수가 4인 행렬, 행은 알아서 맞춰
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23]])
A.reshape(-1) # 다시 길이가 24인 벡터로
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23])

.shape

A = np.array(3.14) # Scalar, 0d array
A.shape
()
A = np.array([3.14]) # Vector, 1d array
A.shape
(1,)
A = np.array([[3.14]]) # Matrix, 2d array
A.shape
(1, 1)
A = np.array([[[3.14]]]) # Tensor, 3d array
A.shape
(1, 1, 1)
A = np.array([[1,2,3],[2,5,6],[4,4,2]])
A.shape
(3, 3)

.T

A = np.arange(4).reshape(2,2)
A
array([[0, 1],
       [2, 3]])
A.T # 전치행렬
array([[0, 2],
       [1, 3]])

np.linalg.inv

np.linalg.inv(A) # 역행렬
array([[-1.5,  0.5],
       [ 1. ,  0. ]])

@

A @ np.linalg.inv(A)
array([[1., 0.],
       [0., 1.]])

np.concatenate

A = np.array([1,2])
B = np.array([4,5])
np.concatenate([A, B])
array([1, 2, 4, 5])
A = np.arange(4).reshape(2,2)
B = np.arange(10,14).reshape(2,2)
np.concatenate([A, B]) # axis = 0이 생략되어 있다.
array([[ 0,  1],
       [ 2,  3],
       [10, 11],
       [12, 13]])
A=np.array(range(4)).reshape(2,2) 
B=np.array(range(2)).reshape(2,1)  
np.concatenate([a,b],axis=1) # 꼭 같은 차원일 필요는 없고, 붙여지는 부분의 길이만 같으면 됨
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [82], in <cell line: 3>()
      1 A=np.array(range(4)).reshape(2,2) 
      2 B=np.array(range(2)).reshape(2,1)  
----> 3 np.concatenate([a,b],axis=1)

NameError: name 'a' is not defined
A = np.arange(4).reshape(2,2)
B = np.arange(10,14).reshape(2,2)
np.concatenate([A, B], axis=1)
A = np.array(range(2*3*4)).reshape(2,3,4)
B = - A
A, B
np.concatenate([A,B], axis=0)
np.concatenate([A,B], axis=1)
np.concatenate([A,B], axis=2)

np.stack

Warning :

A = np.array([1,2,3])
B = np.array([2,3,4])
np.concatenate([A,B], axis = 1)
---------------------------------------------------------------------------
AxisError                                 Traceback (most recent call last)
Input In [83], in <cell line: 3>()
      1 A = np.array([1,2,3])
      2 B = np.array([2,3,4])
----> 3 np.concatenate([A,B], axis = 1)

File <__array_function__ internals>:180, in concatenate(*args, **kwargs)

AxisError: axis 1 is out of bounds for array of dimension 1
A = np.array([1,2,3])
B = np.array([2,3,4])
np.stack([A,B], axis=0)
array([[1, 2, 3],
       [2, 3, 4]])
np.stack([A,B], axis=1)
array([[1, 2],
       [2, 3],
       [3, 4]])
A = np.arange(3*4*5).reshape(3,4,5) 
B = - A

A.shape, B.shape
((3, 4, 5), (3, 4, 5))
np.stack([A,B], axis = 0)

array([[[[  0,   1,   2,   3,   4],
         [  5,   6,   7,   8,   9],
         [ 10,  11,  12,  13,  14],
         [ 15,  16,  17,  18,  19]],

        [[ 20,  21,  22,  23,  24],
         [ 25,  26,  27,  28,  29],
         [ 30,  31,  32,  33,  34],
         [ 35,  36,  37,  38,  39]],

        [[ 40,  41,  42,  43,  44],
         [ 45,  46,  47,  48,  49],
         [ 50,  51,  52,  53,  54],
         [ 55,  56,  57,  58,  59]]],


       [[[  0,  -1,  -2,  -3,  -4],
         [ -5,  -6,  -7,  -8,  -9],
         [-10, -11, -12, -13, -14],
         [-15, -16, -17, -18, -19]],

        [[-20, -21, -22, -23, -24],
         [-25, -26, -27, -28, -29],
         [-30, -31, -32, -33, -34],
         [-35, -36, -37, -38, -39]],

        [[-40, -41, -42, -43, -44],
         [-45, -46, -47, -48, -49],
         [-50, -51, -52, -53, -54],
         [-55, -56, -57, -58, -59]]]])
np.stack([A,B], axis = 0).shape # axis = 0 <==> axis = -4
(2, 3, 4, 5)
np.stack([A,B], axis = 1).shape # axis = 1 <==> axis = -3
(3, 2, 4, 5)
np.stack([A,B], axis = 2).shape # axis = 2 <==> axis = -2
(3, 4, 2, 5)
np.stack([A,B], axis = 3).shape # axis = 3 <==> axis = -1
(3, 4, 5, 2)

Difference between np.concatenate and np.stack

np.concatenate는 축의 총 개수를 유지하면서 결합한다.

np.stack은 축의 개수를 하나 증가시키면서 결합한다.

np.vstack

A = np.arange(6)
B = - A
np.vstack([A, B])
array([[ 0,  1,  2,  3,  4,  5],
       [ 0, -1, -2, -3, -4, -5]])

np.hstack

A = np.arange(6)
B = - A
np.hstack([A, B])
array([ 0,  1,  2,  3,  4,  5,  0, -1, -2, -3, -4, -5])

np.append

A = np.arange(30).reshape(5,6)
B = - np.arange(8).reshape(2,2,2)
A.shape, B.shape
((5, 6), (2, 2, 2))
np.append(A, B) # 다 풀어서 더한다.
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,  0, -1, -2, -3,
       -4, -5, -6, -7])
A = np.arange(2*3*4).reshape(2,3,4)
B = - A
A, B
(array([[[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]],
 
        [[12, 13, 14, 15],
         [16, 17, 18, 19],
         [20, 21, 22, 23]]]),
 array([[[  0,  -1,  -2,  -3],
         [ -4,  -5,  -6,  -7],
         [ -8,  -9, -10, -11]],
 
        [[-12, -13, -14, -15],
         [-16, -17, -18, -19],
         [-20, -21, -22, -23]]]))
A.shape, B.shape, np.append(A, B, axis = 0).shape
((2, 3, 4), (2, 3, 4), (4, 3, 4))
np.append(A, B, axis = 0)
array([[[  0,   1,   2,   3],
        [  4,   5,   6,   7],
        [  8,   9,  10,  11]],

       [[ 12,  13,  14,  15],
        [ 16,  17,  18,  19],
        [ 20,  21,  22,  23]],

       [[  0,  -1,  -2,  -3],
        [ -4,  -5,  -6,  -7],
        [ -8,  -9, -10, -11]],

       [[-12, -13, -14, -15],
        [-16, -17, -18, -19],
        [-20, -21, -22, -23]]])

np.diff

A = np.array([1,2,4,6,7])
np.diff(A)
array([1, 2, 2, 1])
np.diff(np.diff(A))
array([ 1,  0, -1])
np.diff(A, prepend=100) # np.diff(np.array([100] + A.tolist()) ), 즉 맨 앞에 100을 추가하여 차분
array([-99,   1,   2,   2,   1])
np.diff(A, append=100) # np.diff(np.array(A.tolist() + [100]) ), 즉 맨 뒤에 100을 추가하여 차분
array([ 1,  2,  2,  1, 93])
A = np.arange(24).reshape(4,6)
A
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23]])
np.diff(A, axis = 0)
array([[6, 6, 6, 6, 6, 6],
       [6, 6, 6, 6, 6, 6],
       [6, 6, 6, 6, 6, 6]])
np.diff(A, axis = 1)
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]])

np.where

A = np.array([0,0,0,1,0])
np.where(A==1) # 조건을 만족하는 인덱스를 반환
(array([3], dtype=int64),)
np.random.seed(43052)
A = np.random.randn(12).reshape(3,4)
np.where(A<0) # 조건을 만족하는 인덱스가 (1,2), (1,3), (2,0), (2,1), (2,3) 이라는 의미
(array([1, 1, 2, 2, 2], dtype=int64), array([2, 3, 0, 1, 3], dtype=int64))
A[np.where(A<0)]
array([-1.66307542, -1.38277318, -1.92684484, -1.4862163 , -0.03488725])
np.where(A<0, 0, A) # 조건이 True이면 0, False이면 A
array([[0.38342049, 1.0841745 , 1.14277825, 0.30789368],
       [0.23778744, 0.35595116, 0.        , 0.        ],
       [0.        , 0.        , 0.00692519, 0.        ]])
np.where(A<0, 5, 1) # 조건이 True이면 0, False이면 1
array([[1, 1, 1, 1],
       [1, 1, 5, 5],
       [5, 5, 1, 5]])

np.argwhere

A = np.array([0,0,0,1,0])
np.argwhere(A==1)
array([[3]], dtype=int64)
np.random.seed(43052)
A = np.random.randn(12).reshape(3,4)
np.argwhere(A<0) # 조건을 만족하는 인덱스가 (1,2), (1,3), (2,0), (2,1), (2,3) 이라는 의미
array([[1, 2],
       [1, 3],
       [2, 0],
       [2, 1],
       [2, 3]], dtype=int64)
A[np.argwhere(A<0)] # 불가능
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Input In [106], in <cell line: 1>()
----> 1 A[np.argwhere(A<0)]

IndexError: index 3 is out of bounds for axis 0 with size 3

Difference between np.where and np.argwhere

np.where는 인덱스의 좌표를 읽는 가독성이 떨어지지만 조건에 맞는 원소를 출력하거나 처리하기에 좋다.

np.argwhere는 인덱스의 좌표를 읽는 가독성은 좋지만 조건에 맞는 원소를 출력하거나 처리하기에 좋지 못하다.

np.ix_

A = np.arange(12).reshape(3,4)
A
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
  • A[[0,1], [0,1]]이 A[0:2, 0:2]를 의미하게 하려면 아레와 같이 np.ix_를 사용한다.
A[np.ix_([0,1],[0,1])]
array([[0, 1],
       [4, 5]])

Operations

.sum

A = np.array([1,2,3])
A.sum()
6

.mean

A = np.array([1,2,3])
A.mean()
2.0

.min

A = np.array([1,2,3])
A.min()
1

.max

A = np.array([1,2,3])
A.max()
3

.prod

A = np.array([1,2,3])
A.prod()
6

.std

A = np.arange(1,20)
A.std() # 분포를 n으로 나누는 것이 default이다.
5.477225575051661
A = A = np.array([1,2,3])
A.std(ddof=1) # ddof 옵션을 사용하여 분포를 n-1로 나눈다.
1.0
A = A = np.array([1,2,3])
A.std(ddof=2) # ddof 옵션을 사용하여 분포를 n-1로 나눈다.
1.4142135623730951

.argmin

A = np.array([1,2,3]) # 가장 작은 값의 인덱스를 리턴
A.argmin()
0
np.random.seed(43052)
A = np.random.randn(4*5).reshape(4,5)
A
array([[ 0.38342049,  1.0841745 ,  1.14277825,  0.30789368,  0.23778744],
       [ 0.35595116, -1.66307542, -1.38277318, -1.92684484, -1.4862163 ],
       [ 0.00692519, -0.03488725, -0.34357323,  0.70895648, -1.55100608],
       [ 1.34565583, -0.05654272, -0.83017342, -1.46395159, -0.35459593]])
A.argmin(axis = 0)
array([2, 1, 1, 1, 2], dtype=int64)
A.argmin(axis = 1)
array([4, 3, 4, 3], dtype=int64)

.argmax

A = np.array([1,2,3]) # 가장 큰 값의 인덱스를 리턴
A.argmax()
2
np.random.seed(43052)
A = np.random.randn(4*5).reshape(4,5)
A
array([[ 0.38342049,  1.0841745 ,  1.14277825,  0.30789368,  0.23778744],
       [ 0.35595116, -1.66307542, -1.38277318, -1.92684484, -1.4862163 ],
       [ 0.00692519, -0.03488725, -0.34357323,  0.70895648, -1.55100608],
       [ 1.34565583, -0.05654272, -0.83017342, -1.46395159, -0.35459593]])
A.argmax(axis = 0)
array([3, 0, 0, 2, 0], dtype=int64)
A.argmax(axis = 1)
array([2, 0, 3, 0], dtype=int64)

.cumsum

A = np.array([1,2,3,4])
A.cumsum() # 누적합
array([ 1,  3,  6, 10])

.cumprod

A = np.array([1,2,3,4])
A.cumprod() # 누적곱
array([ 1,  2,  6, 24])
A = np.array([2**i for i in np.arange(10)])
A
array([  1,   2,   4,   8,  16,  32,  64, 128, 256, 512])
A.cumprod()
array([        1,         2,         8,        64,      1024,     32768,
         2097152, 268435456,         0,         0])

Applications

Solving System of Equations

$\begin{cases} y+z+w = 3 \\ x+z+w = 3 \\ x+y+w = 3 \\ x+y+z = 3 \end{cases}$

$\begin{bmatrix} 0 & 1 & 1 & 1 \\ 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 1 \\ 1 & 1 & 1 & 0 \end{bmatrix} \begin{bmatrix} x \\ y \\ z \\ w \end{bmatrix} = \begin{bmatrix} 3 \\ 3 \\ 3 \\ 3 \end{bmatrix}$

$ \begin{bmatrix} 0 & 1 & 1 & 1 \\ 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 1 \\ 1 & 1 & 1 & 0 \end{bmatrix}^{\,-1} \begin{bmatrix} 0 & 1 & 1 & 1 \\ 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 1 \\ 1 & 1 & 1 & 0 \end{bmatrix} \begin{bmatrix} x \\ y \\ z \\ w \end{bmatrix} = \begin{bmatrix} 0 & 1 & 1 & 1 \\ 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 1 \\ 1 & 1 & 1 & 0 \end{bmatrix}^{\,-1} \begin{bmatrix} 3 \\ 3 \\ 3 \\ 3 \end{bmatrix}$

$ \begin{bmatrix} x \\ y \\ z \\ w \end{bmatrix} = \begin{bmatrix} 0 & 1 & 1 & 1 \\ 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 1 \\ 1 & 1 & 1 & 0 \end{bmatrix}^{\,-1} \begin{bmatrix} 3 \\ 3 \\ 3 \\ 3 \end{bmatrix}$

v = 'x', 'y', 'z'
A = np.linalg.inv(np.array([[0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0]]))
B = np.array([3,3,3,3]).reshape(4,1)

answer = A@B.reshape(-1)
for v, i in zip(v, answer): print(v, ':', i)
x : 1.0
y : 1.0
z : 1.0