728x90
🐼 혹시나 판다스 공부로 넘어가고 싶다면??
2022.02.22 - [😀 Language/- Python] - [Pandas] 판다스 튜토리얼 (Pandas quickstart)공부해보기
In [1]:
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))
#티스토리 업로드 원활하게:-)
Numpy (Quickstart Tutorial)¶
1. 기초 개념¶
In [2]:
import numpy as np
1) example¶
In [3]:
# (3, 5) 크기의 2D 배열
a= np.arange(15).reshape(3,5)
a
Out[3]:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
- ndarray.shape : 배열의 각 축(axis)의 크기
- ndarray.ndim : 축의 개수(Dimension)
- ndarray.dtype : 각 요소(Element)의 타입
- ndarray.itemsize : 각 요소(Element)의 타입의 bytes 크기
- ndarray.size : 전체 요소(Element)의 개수
In [4]:
a.ndim
Out[4]:
2
In [5]:
a.shape
Out[5]:
(3, 5)
In [6]:
a.dtype
Out[6]:
dtype('int32')
In [7]:
a.itemsize
Out[7]:
4
In [8]:
a.size
Out[8]:
15
In [9]:
type(a)
Out[9]:
numpy.ndarray
2) 배열 생성하기¶
- np.array()를 이용하여 튜플이나 리스트 입력으로 numpy.ndarray를 만들 수 있습니다
In [10]:
a = np.array([2,3,4])
a
Out[10]:
array([2, 3, 4])
In [11]:
a.dtype
Out[11]:
dtype('int32')
In [12]:
b= np.array([1.2,3.5,5.1])
b
Out[12]:
array([1.2, 3.5, 5.1])
In [13]:
b.dtype
Out[13]:
dtype('float64')
- 주의할점 연속된 데이터(시퀀스형)으로 입력하여 numpy를 만들어야한다.
In [14]:
# 오류 발생하는 경우 example
a= np.array(1,2,3,4)
a
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_23760/1305017564.py in <module>
1 # 오류 발생하는 경우 example
----> 2 a= np.array(1,2,3,4)
3 a
TypeError: array() takes from 1 to 2 positional arguments but 4 were given
In [39]:
# 수정하기
a= np.array([1,2,3,4])
a
Out[39]:
array([1, 2, 3, 4])
- 2D 배열이나 3D배열등도 마찬가지로 ok
In [40]:
b= np.array([(1,2,3),(4,5,6)])
b
Out[40]:
array([[1, 2, 3],
[4, 5, 6]])
- 복소수값도 생성 가능하다
dtype = complex
In [41]:
c= np.array([[1,2],[3,4]], dtype=complex)
c
Out[41]:
array([[1.+0.j, 2.+0.j],
[3.+0.j, 4.+0.j]])
np.zeros(shape)
: 0으로 구성된 N차원 배열 생성np.ones(shape)
: 1로 구성된 N차원 배열 생성np.empty(shape)
: 초기화되지 않은 N차원 배열 생성
In [42]:
np.zeros((3,4))
Out[42]:
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
In [43]:
np.ones((2,3,4), dtype=np.int16)
Out[43]:
array([[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]],
[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]], dtype=int16)
In [44]:
np.empty((2,3))
Out[44]:
array([[0., 0., 0.],
[0., 0., 0.]])
np.arange()
: N 만큼 차이나는 숫자 생성np.linspace()
: N 등분한 숫자 생성
In [45]:
np.arange(10,30,5) #10이상 30미만까지 5씩 차이
Out[45]:
array([10, 15, 20, 25])
In [46]:
np.arange(0,2,0.3)
Out[46]:
array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])
In [47]:
np.linspace(0,99,100) #0부터 99까지 100등분
Out[47]:
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., 60., 61., 62., 63., 64.,
65., 66., 67., 68., 69., 70., 71., 72., 73., 74., 75., 76., 77.,
78., 79., 80., 81., 82., 83., 84., 85., 86., 87., 88., 89., 90.,
91., 92., 93., 94., 95., 96., 97., 98., 99.])
3) 배열 출력하기¶
In [48]:
a= np.arange(6)
a
Out[48]:
array([0, 1, 2, 3, 4, 5])
In [49]:
b= np.arange(12).reshape(4,3)
b
Out[49]:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
In [50]:
c= np.arange(24).reshape(2,3,4)
c
Out[50]:
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.ndarray.reshape()
In [51]:
np.arange(10)
Out[51]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [52]:
np.arange(10).reshape(2,5)
Out[52]:
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
4) 기본연산 (Basic Operations)¶
- 수치연산은 각 요소들끼리 연산이 적용된다.
In [53]:
a= np.array([20,30,40,50])
b= np.arange(4)
print(a)
print(b)
[20 30 40 50]
[0 1 2 3]
In [54]:
c= a-b
c
Out[54]:
array([20, 29, 38, 47])
In [55]:
b**2
Out[55]:
array([0, 1, 4, 9], dtype=int32)
In [56]:
10*np.sin(a)
Out[56]:
array([ 9.12945251, -9.88031624, 7.4511316 , -2.62374854])
In [57]:
a<35
Out[57]:
array([ True, True, False, False])
*
: 각각의 원소끼리 곱셈 (Elementwise product, Hadamard product)@
: 행렬 곱셈 (Matrix product).dot()
: 행렬 내적 (dot product)
In [58]:
a= np.array([[1,1],[0,1]])
b= np.array([[2,0],[3,4]])
print(a)
print(b)
[[1 1]
[0 1]]
[[2 0]
[3 4]]
In [59]:
a*b
Out[59]:
array([[2, 0],
[0, 4]])
In [60]:
a@b
Out[60]:
array([[5, 4],
[3, 4]])
In [61]:
a.dot(b)
Out[61]:
array([[5, 4],
[3, 4]])
- .dtype이 다르면 타입이 큰쪽(int < float < complex)으로 자동으로 변경된다.
In [62]:
a= np.ones(3,dtype=np.int32)
b= np.linspace(0, np.pi, 3) #0부터 파이까지 3등분
print(a)
print(b)
[1 1 1]
[0. 1.57079633 3.14159265]
In [63]:
a+b
Out[63]:
array([1. , 2.57079633, 4.14159265])
In [64]:
(a+b).dtype
Out[64]:
dtype('float64')
In [65]:
c= np.exp((a+b)*1j)
c
Out[65]:
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
-0.54030231-0.84147098j])
In [66]:
c.dtype
Out[66]:
dtype('complex128')
.sum()
: 모든 요소의 합.min()
: 모든 요소 중 최소값.max()
: 모든 요소 중 최대값.argmin()
: 모든 요소 중 최소값의 인덱스.argmax()
: 모든 요소 중 최대값의 인덱스.cumsum()
: 모든 요소의 누적합
In [67]:
a= np.arange(8).reshape(2,4)**2
a
Out[67]:
array([[ 0, 1, 4, 9],
[16, 25, 36, 49]], dtype=int32)
In [68]:
a.sum()
Out[68]:
140
In [69]:
a.min()
Out[69]:
0
In [70]:
a.max()
Out[70]:
49
In [71]:
a.argmin()
Out[71]:
0
In [72]:
a.argmax()
Out[72]:
7
In [73]:
a.cumsum()
Out[73]:
array([ 0, 1, 5, 14, 30, 55, 91, 140], dtype=int32)
- axis를 입력하여 계산이 가능하다!
- axis=0은 열 기준 / axis=1은 행 기준
In [74]:
b= np.arange(12).reshape(3,4)
b
Out[74]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [75]:
b.sum(axis=0)
Out[75]:
array([12, 15, 18, 21])
In [76]:
b.sum(axis=1)
Out[76]:
array([ 6, 22, 38])
In [77]:
b.max(axis=0)
Out[77]:
array([ 8, 9, 10, 11])
In [78]:
b.max(axis=1)
Out[78]:
array([ 3, 7, 11])
In [79]:
b.argmax(axis=0)
Out[79]:
array([2, 2, 2, 2], dtype=int64)
In [80]:
b.argmax(axis=1)
Out[80]:
array([3, 3, 3], dtype=int64)
5) 범용 함수 (Universal Functions)¶
- Math operations: https://numpy.org/doc/1.18/reference/ufuncs.html#available-ufuncs
In [81]:
a= np.arange(9).reshape(3,3)
a
Out[81]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [82]:
b= np.arange(10,19).reshape(3,3)
b
Out[82]:
array([[10, 11, 12],
[13, 14, 15],
[16, 17, 18]])
In [83]:
np.add(a,b)
Out[83]:
array([[10, 12, 14],
[16, 18, 20],
[22, 24, 26]])
In [84]:
np.subtract(a,b)
Out[84]:
array([[-10, -10, -10],
[-10, -10, -10],
[-10, -10, -10]])
In [85]:
np.sqrt(a) #제곱근
Out[85]:
array([[0. , 1. , 1.41421356],
[1.73205081, 2. , 2.23606798],
[2.44948974, 2.64575131, 2.82842712]])
In [86]:
np.positive(a) #제곱
Out[86]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
6) 인덱싱, 슬라이싱, 반복¶
In [87]:
np.arange(10)
Out[87]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [88]:
#예제 생성
a= np.arange(10)**3
a
Out[88]:
array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729], dtype=int32)
In [89]:
a[2]
Out[89]:
8
In [90]:
a[2:5]
Out[90]:
array([ 8, 27, 64], dtype=int32)
In [91]:
a[:6:2]
Out[91]:
array([ 0, 8, 64], dtype=int32)
In [92]:
#0,2,4인덱스 값을 1000으로 변경
a[:6:2]=1000
a
Out[92]:
array([1000, 1, 1000, 27, 1000, 125, 216, 343, 512, 729],
dtype=int32)
In [93]:
for i in a:
print(i**(1/3.))
9.999999999999998
1.0
9.999999999999998
3.0
9.999999999999998
5.0
5.999999999999999
6.999999999999999
7.999999999999999
8.999999999999998
np.fromfunction()
인덱스 번호를 가지고 함수 정의하여 생성하기
In [94]:
def f(x,y):
return 10*x +y
b= np.fromfunction(f, (5,4), dtype=int)
In [95]:
b # x좌표는 십의 자리 / y좌표는 일의 자리
Out[95]:
array([[ 0, 1, 2, 3],
[10, 11, 12, 13],
[20, 21, 22, 23],
[30, 31, 32, 33],
[40, 41, 42, 43]])
...
은 차원이 너무 많을 때 실수를 줄여줄 수 있습니다. 만약 x가 5차원이라고 할 때 아래 처럼 표현할 수 있습니다.
In [96]:
c = np.array( [[[ 0, 1, 2],
[ 10, 12, 13]],
[[100,101,102],
[110,112,113]]])
In [97]:
c.shape
Out[97]:
(2, 2, 3)
In [98]:
c[1, ...]
Out[98]:
array([[100, 101, 102],
[110, 112, 113]])
- 반복문은 axis=0 기준으로 적용
In [99]:
b
Out[99]:
array([[ 0, 1, 2, 3],
[10, 11, 12, 13],
[20, 21, 22, 23],
[30, 31, 32, 33],
[40, 41, 42, 43]])
In [100]:
for i in b:
print(i)
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]
In [101]:
for i in b.flat:
print(i)
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43
2. Shape 변경¶
1) shape 변경¶
np.ndarray
의 shape를 다양한 방법으로 변경할 수 있습니다..ravel()
은 1차원으로,.reshape()
는 지정한 차원으로,.T
는 전치(Transpose) 변환을 할 수 있습니다.- 하지만 데이터 원본은 변경시키지 않고 복사하여 연산한 결과가 return 됩니다.
In [102]:
rg= np.random.default_rng(1) #난수생성
In [103]:
a= np.floor(10 * rg.random((3,4)))
a
Out[103]:
array([[5., 9., 1., 9.],
[3., 4., 8., 4.],
[5., 0., 7., 5.]])
In [104]:
a.shape
Out[104]:
(3, 4)
In [105]:
a.ravel() #1차원으로 바꾸기
Out[105]:
array([5., 9., 1., 9., 3., 4., 8., 4., 5., 0., 7., 5.])
In [106]:
a.reshape(2,6)
Out[106]:
array([[5., 9., 1., 9., 3., 4.],
[8., 4., 5., 0., 7., 5.]])
In [107]:
a.T
Out[107]:
array([[5., 3., 5.],
[9., 4., 0.],
[1., 8., 7.],
[9., 4., 5.]])
.resize()
는 위의 .reshape()와 동일한 기능이지만 원본 데이터 자체를 변경시킵니다..reshape()
를 할 때 차원값에 -1를 입력하면 -1 부분은 자동으로 차원을 채워줍니다. 당연히 여러 차원에서 -1는 하나만 사용할 수 있고 나머지가 지정된 결과를 바탕으로 자동으로 계산해줍니다
In [108]:
a
Out[108]:
array([[5., 9., 1., 9.],
[3., 4., 8., 4.],
[5., 0., 7., 5.]])
In [109]:
a.resize((2,6)) #reshape와 다르게 원본을 변경함
a
Out[109]:
array([[5., 9., 1., 9., 3., 4.],
[8., 4., 5., 0., 7., 5.]])
In [110]:
a.reshape(3,-1) #-1라고 써도 저절로 4라고 채워줌
Out[110]:
array([[5., 9., 1., 9.],
[3., 4., 8., 4.],
[5., 0., 7., 5.]])
2) 데이터 쌓기¶
np.vstack()
: 데이터 합치기, axis=0 (행)기준으로 쌓음np.hstack()
: 데이터 합치기, axis=1 (열)기준으로 쌓음
In [111]:
#난수 a 생성
a= np.floor(10*rg.random((2,2)))
a
Out[111]:
array([[3., 7.],
[3., 4.]])
In [112]:
#난수 b 생성
b= np.floor(10*rg.random((2,2)))
b
Out[112]:
array([[1., 4.],
[2., 2.]])
In [113]:
np.vstack((a,b))
Out[113]:
array([[3., 7.],
[3., 4.],
[1., 4.],
[2., 2.]])
In [114]:
np.hstack((a,b))
Out[114]:
array([[3., 7., 1., 4.],
[3., 4., 2., 2.]])
3) 데이터 쪼개기¶
np.vsplit(행열,x)
: axis=0 기준으로 x등분np.hsplit(행열, x)
:axis=1 기준으로 x등분
In [115]:
#난수 생성
npr= np.random.default_rng(1)
In [116]:
a= np.floor(10*npr.random((6,4)))
a
Out[116]:
array([[5., 9., 1., 9.],
[3., 4., 8., 4.],
[5., 0., 7., 5.],
[3., 7., 3., 4.],
[1., 4., 2., 2.],
[7., 2., 4., 9.]])
In [117]:
np.vsplit(a,3)
Out[117]:
[array([[5., 9., 1., 9.],
[3., 4., 8., 4.]]),
array([[5., 0., 7., 5.],
[3., 7., 3., 4.]]),
array([[1., 4., 2., 2.],
[7., 2., 4., 9.]])]
In [118]:
np.hsplit(a,2)
Out[118]:
[array([[5., 9.],
[3., 4.],
[5., 0.],
[3., 7.],
[1., 4.],
[7., 2.]]),
array([[1., 9.],
[8., 4.],
[7., 5.],
[3., 4.],
[2., 2.],
[4., 9.]])]
3. 데이터 복사¶
1) 복사되지 않는 경우¶
In [119]:
a = np.array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [120]:
b=a
b is a
Out[120]:
True
In [121]:
print(id(a))
print(id(b))
2121701626576
2121701626576
2) 얕은 복사(View or Shallow Copy)¶
view()
를 통해 Shallow Copy를 할 수 있습니다.
In [122]:
a
Out[122]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [123]:
c= a.view()
c
Out[123]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [124]:
c is a
Out[124]:
False
In [125]:
print(id(c))
print(id(a))
2121700994384
2121701626576
3) 깊은 복사 - Deep Copy¶
.copy()
를 이용하면 Deep Copy를 할 수 있습니다
In [126]:
d = a.copy()
d
Out[126]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [127]:
d is a
Out[127]:
False
In [128]:
print(id(d))
print(id(a))
2121700655728
2121701626576
브로드캐스팅 (Broadcasting rules)¶
In [129]:
np.array([1,2,3,4,5])*2
Out[129]:
array([ 2, 4, 6, 8, 10])
In [130]:
np.arange(4)
Out[130]:
array([0, 1, 2, 3])
In [131]:
np.arange(4)* 2
Out[131]:
array([0, 2, 4, 6])
In [132]:
np.ones((3,4)) * np.arange(4)
Out[132]:
array([[0., 1., 2., 3.],
[0., 1., 2., 3.],
[0., 1., 2., 3.]])
In [133]:
np.arange(3).reshape((3,1))*np.arange(3)
Out[133]:
array([[0, 0, 0],
[0, 1, 2],
[0, 2, 4]])
5. 인덱싱 심화편¶
1) 인덱스 배열로 인덱싱하기¶
In [134]:
#예제1
a= np.arange(12)**2
a
Out[134]:
array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121],
dtype=int32)
In [135]:
i = np.array([1,1,3,8,5])
a[i]
Out[135]:
array([ 1, 1, 9, 64, 25], dtype=int32)
In [136]:
# 예제2
j = np.array([[3,4],[9,7]])
j
Out[136]:
array([[3, 4],
[9, 7]])
In [137]:
a[j]
Out[137]:
array([[ 9, 16],
[81, 49]], dtype=int32)
In [138]:
# 예제3
a=np.arange(5)
a
Out[138]:
array([0, 1, 2, 3, 4])
In [139]:
a[[1,3,4]]=0
a
Out[139]:
array([0, 0, 2, 0, 0])
In [140]:
# 예제4
b= np.arange(5)
b
Out[140]:
array([0, 1, 2, 3, 4])
In [141]:
b[[0,1,2]]+=1
b
Out[141]:
array([1, 2, 3, 3, 4])
2) Bool로 인덱싱¶
In [142]:
a= np.arange(12).reshape(3,4)
b= a>4
In [143]:
print(a)
print(b)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[False False False False]
[False True True True]
[ True True True True]]
In [144]:
a[b]
Out[144]:
array([ 5, 6, 7, 8, 9, 10, 11])
In [145]:
a[b]=0
a
Out[145]:
array([[0, 1, 2, 3],
[4, 0, 0, 0],
[0, 0, 0, 0]])
3) .ix_( ) 함수¶
- 서로 다른 Shape를 가진 배열들을 묶어서 처리할 수 있습니다.
In [146]:
a = np.array([2,3,4,5])
b = np.array([8,5,4])
c = np.array([5,4,6,8,3])
In [147]:
ax,bx,cx = np.ix_(a,b,c)
In [148]:
ax
Out[148]:
array([[[2]],
[[3]],
[[4]],
[[5]]])
In [149]:
bx
Out[149]:
array([[[8],
[5],
[4]]])
In [150]:
cx
Out[150]:
array([[[5, 4, 6, 8, 3]]])
In [151]:
print(ax.shape, bx.shape, cx.shape)
(4, 1, 1) (1, 3, 1) (1, 1, 5)
In [152]:
result = ax + bx * cx
result
Out[152]:
array([[[42, 34, 50, 66, 26],
[27, 22, 32, 42, 17],
[22, 18, 26, 34, 14]],
[[43, 35, 51, 67, 27],
[28, 23, 33, 43, 18],
[23, 19, 27, 35, 15]],
[[44, 36, 52, 68, 28],
[29, 24, 34, 44, 19],
[24, 20, 28, 36, 16]],
[[45, 37, 53, 69, 29],
[30, 25, 35, 45, 20],
[25, 21, 29, 37, 17]]])
In [153]:
result[3,2,4]
Out[153]:
17
In [154]:
#따로따로 계산했을때랑 값 비교해보자
a[3]+b[2]*c[4]
Out[154]:
17
6. 선형대수(Linear Algebra)¶
In [155]:
a= np.array([[1.0,2.0],[3.0,4.0]])
a
Out[155]:
array([[1., 2.],
[3., 4.]])
In [156]:
a.transpose()
Out[156]:
array([[1., 3.],
[2., 4.]])
In [157]:
np.linalg.inv(a)
Out[157]:
array([[-2. , 1. ],
[ 1.5, -0.5]])
In [158]:
u = np.eye(2)
u
Out[158]:
array([[1., 0.],
[0., 1.]])
In [159]:
j = np.array([[1.0,-1.0],[1.0,0.0]])
j
Out[159]:
array([[ 1., -1.],
[ 1., 0.]])
In [160]:
j@j
Out[160]:
array([[ 0., -1.],
[ 1., -1.]])
In [161]:
np.trace(u)
Out[161]:
2.0
In [162]:
y= np.array([[5.],[7.]])
np.linalg.solve(a,y)
Out[162]:
array([[-3.],
[ 4.]])
In [163]:
np.linalg.eig(j)
Out[163]:
(array([0.5+0.8660254j, 0.5-0.8660254j]),
array([[0.70710678+0.j , 0.70710678-0.j ],
[0.35355339-0.61237244j, 0.35355339+0.61237244j]]))
위 코드식은 여기 github에 올려놓았어여 👉 https://github.com/LIMSONA/Big_Data_Study/blob/main/Numpy%20(Quickstart%20Tutorial).ipynb
728x90
'😀 Language > - Python' 카테고리의 다른 글
[Pandas] EDA 자주 사용하는 코드 모아보기 😆 (0) | 2022.02.24 |
---|---|
[Pandas] 판다스 튜토리얼 (Pandas quickstart)공부해보기 (0) | 2022.02.22 |
[파이썬] 주사위 30개를 10000번 던졌을 때 정규분포표 그리기 (+중심극한) (0) | 2022.01.25 |
[샛길공부] int( )함수 자세히 알아보기! int(값,진수) (그의 매력을 파헤쳐보자) (0) | 2022.01.22 |
[pymysql 모듈] 파이썬과 mysql 연동시키기! (0) | 2022.01.19 |