array(object, dtype=None, *, copy=True, order='K', subok=False, ndmin=0, like=None)
object
를 array로 변환한다.
C
: C-order, Row-Major(행 우선) 방식으로 C
언어 스타일로 저장한다.
>>> arr = np.array(range(24)).reshape(3, 4, 2) >>> print(arr) [[[ 0 1] [ 2 3] [ 4 5] [ 6 7]] [[ 8 9] [10 11] [12 13] [14 15]] [[16 17] [18 19] [20 21] [22 23]]] >>> arr.ravel('C') #numpy.ravel은 1차원 배열로 변경해주는 함수이다. 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])
F
: F-order, Column-Major(열 우선)으로 Fortran
스타일로 저장한다.
>>> arr.ravel('F') array(array([ 0, 8, 16, 2, 10, 18, 4, 12, 20, 6, 14, 22, 1, 9, 17, 3, 11, 19, 5, 13, 21, 7, 15, 23]))
A
: a
가 'Fortran contiguous'이면 F-order, 아니면 C-order
>>> arr.ravel('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])
K
: a
와 가장 근사한 형태로 맞춰서 저장한다.
>>> arr.ravel('K') 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])
subok
subok=True
이면 입력한 a
의 class로 반환한다.
subok=Fasle
이면 base class인 array(배열)로 반환한다.
>>> arr = np.mat([1, 3, 5, 7, 9]) >>> print(type(arr)) <class 'numpy.matrix'> >>> arr_copy = np.copy(arr, subok=False) >>> print(type(arr_copy)) <class 'numpy.ndarray'> >>> arr_copy = np.copy(arr, subok=True) >>> print(type(arr_copy)) <class 'numpy.matrix'>
arange([start,] stop[, step,], dtype=None, *, like=None)
파이썬 내장함수 range()
와 같은 요소를 반환하며, 일차원 배열을 반환한다.
>>> np.arange(10) array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
zeros(shape[, dtype=float, order='C', *, like=None])
0으로 채운 shape
배열을 반환한다. dtype
의 Default 값은 numpy.float64이기 때문에 출력을 하면 실수 형태로 표현된다.
>>> zero_vector = np.zeros(3) >>> zero_vector array([0., 0., 0.]) >>> zero_matrix = np.zeros((2, 2)) >>> zero_matrix array([[0., 0.], [0., 0.]]) >>> zero_tensor = np.zeros((3, 4, 5), dtype=int) array([[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]])
ones(shape[, dtype=None, order='C', *, like=None])
1로 채운 shape
배열을 반환한다.
>>> one_matrix = np.ones((2, 3), dtype=int) >>> one_matrix array([[1, 1, 1], [1, 1, 1]])
eye(N, M=None, k=0, dtype=<class 'float'>, order='C', *, like=None)
N
×M
(N행 M열, (y, x)) 배열의 대각선을 1로 채우고 나머지는 0으로 채운 단위 행렬(Unit matrix, Identity matrix)을 반환한다. M값이 없으면 N값을 차용하여 N×N 행렬을 반환한다.
>>> unit_matrix = np.eye(2) >>> unit_matrix array([[1., 0.], [0., 1.]]) >>> unit_matrix = np.eye(5, 6, k=-1) >>> unit_matrix array([[0., 0., 0., 0., 0., 0.], [1., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0.], [0., 0., 0., 1., 0., 0.]]) >>> unit_matrix = np.eye(5, 6, k=1) >>> unit_matrix array([[0., 1., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0.], [0., 0., 0., 1., 0., 0.], [0., 0., 0., 0., 1., 0.], [0., 0., 0., 0., 0., 1.]])
identity(n, dtype=None, *, like=None)
N
×N
단위 행렬을 반환한다. eye와 차이점은 k값이 없고 행과 열을 각각 지정할 수 없어, 정사각 행렬만 가능하다는 점이다.
>>> unit_matrix = np.eye(3) >>> unit_matrix array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]])
full(shape, fill_value, dtype=None, order='C', *, like=None)
fill_value로 채운 shape 배열을 반환한다. fill_value가 입력되지 않으면 TypeError를 반환한다. 이 때 fill_value는 list일 수 있으나, list 원소의 개수와 shape 열(x)의 개수가 동일해야 한다.
>>> matrix = np.full((3, 2), 9) >>> matrix array([[9, 9], [9, 9], [9, 9]]) >>> matrix = np.full(3, 9) >>> matrix array([9, 9, 9]) >>> matrix = np.full((2, 4), [0, 1, 2, 3]) >>> matrix array([[0, 1, 2, 3], [0, 1, 2, 3]]) >>> matrix = np.full((2, 4), [0, 1, 2]) >>> matrix ValueError: could not broadcast input array from shape (3,) into shape (2,4)
empty(shape, dtype=float, order='C', *, like=None)
값을 초기화하지 않은(uninitialized) shape
배열을 반환한다. 때문에 배열의 원소는 무작위의 쓰레기 값이 들어가있다.
>>> np.empty([2, 2, 2]) array([[[2.e+000, 2.e+000], [6.e-323, 0.e+000]], [[0.e+000, 0.e+000], [0.e+000, 0.e+000]]])
linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
start
와 stop
을 포함하며,>>> arr = np.linspace(0, 10, num=10) >>> arr array([ 0. , 1.11111111, 2.22222222, 3.33333333, 4.44444444, 5.55555556, 6.66666667, 7.77777778, 8.88888889, 10. ]) >>> arr.dtype dtype('float64') >>> arr = np.linspace(0, 10, num=10, endpoint=False) array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) >>> arr.dtype dtype('float64') >>> print(type(arr)) <class 'numpy.ndarray'> arr = np.linspace(0, 10, num=10, endpoint=False, retstep=True) >>> arr (array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]), 1.0) >>> print(type(arr)) <class 'tuple'>
endpoint: False
이면 stop의 값을 포함하지 않는다.
retstep: True
이면 step을 포함한 tuple
을 반환한다.
random.rand(d0, d1, ..., dn)
무작위의 실수 값이 들어간 배열을 생성한다.
>>> np.random.rand() 0.5746517743788403 >>> np.random.rand(2, 2, 2) array([[[0.97991615, 0.45740781], [0.80219428, 0.52082672]], [[0.33031469, 0.24888061], [0.76583919, 0.83189951]]])
[numpy.random.rand]
random.randint(low, high=None, size=None, dtype=int)
지정된 범위 내에 존재하는 정수값 중 무작위의 정수값이 들어간 배열을 생성한다.
>>> np.random.randint(0) ValueError: low >= high >>> np.random.randint(5, size = 10) array([0, 0, 0, 3, 0, 1, 4, 2, 2, 4])
low와 high 값은 list로 줄 수 있으며, size에서 열(x 축)의 개수와 동일해야 한다. 아래 예시처럼 x축이 4이면
,
,
,
범위의 무작위 값이 할당된다.
>>> np.random.randint([1, 3, 5, 999], size=4) array([ 0, 2, 4, 240]) >>> np.random.randint([1, 3, 5, 999], size=[2, 2, 4]) array([[[ 0, 2, 3, 666], [ 0, 2, 0, 391]], [[ 0, 0, 4, 293], [ 0, 0, 3, 904]]]) >>> np.random.randint(0, [1, 3, 5, 999], size=4) array([ 0, 1, 3, 347])
matrix(data, dtype=None, copy=True)
matrix(행렬)을 생성한다. 행렬과 배열의 차이점은 자료를 참고하자.
shape 모양으로 복사한다.
zeros_like
numpy.zeros_like(a, dtype=None, order='K', subok=True, shape=None)
ones_like
numpy.ones_like(a, dtype=None, order='K', subok=True, shape=None)
full_like
numpy.full_like(a, fill_value, dtype=None, order='K', subok=True, shape=None)
empty_like
numpy.empty_like(prototype, dtype=None, order='K', subok=True, shape=None)
>>> arr = np.arange(6).reshape(3, 2) >>> arr array([[0, 1], [2, 3], [4, 5]]) >>> np.zeros_like(arr) array([[0, 0], [0, 0], [0, 0]]) >>> np.ones_like(arr) array([[1, 1], [1, 1], [1, 1]]) >>> np.full_like(arr, 9) array([[9, 9], [9, 9], [9, 9]]) >>> np.empty_like(arr) array([[2305843009213693952, 1152930266541223069], [ 3, 0], [ 0, 844424930131968]])
reshape(a, newshape, order='C')[source]
array로 변경할 수 있는(array like)a
의 차원을 newshape
로 변경한다.
>>> np.arange(24).reshape(3, 2, 4) # 3d 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]]])
>>> lis = range(24) >>> np.reshape(lis, [3, 2, 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]]])
numpy.resize(a, new_shape)
a
를 new_shape
로 shape를 변경한다. 이 때 a
의 size에 상관없이 new_shape
array를 만들 수 있다. a.size
보다 작으면 a[0]
부터 a[new_shape.size]
까지의 데이터를 사용해서 반환한다. a.size
보다 크면 부족한 부분은 a
의 끝에 a
를 다시 이어붙여 반환한다.
>>> arr = np.arange(24) >>> np.resize(arr, (3, 3, 3)) 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]]])
ndarray.resize(new_shape, refcheck=True)
reshape와 다른 점은 반환 값을 ndarray에 적용한다는 것이다.
>>> arr = np.arange(6) >>> arr.reshape(3, 2) array([[0, 1], [2, 3], [4, 5]]) >>> arr array([0, 1, 2, 3, 4, 5]) >>> arr.resize(3, 2) >>> arr array([[0, 1], [2, 3], [4, 5]]) >>> arr.resize(2, 2, 4) ValueError: cannot resize an array that references or is referenced by another array in this way. Use the np.resize function or refcheck=False >>> arr.resize(2, 2, 4, refcheck=False) >>> arr array([[[0, 1, 2, 3], [4, 5, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0]]])
numpy.split(ary, indices_or_sections, axis=0)
ary
를 indices_or_sections
으로 나눈 list를 반환한다.
indices_or_sections
에 숫자를 묶어서 넣으면 구간으로 쪼개진다.>>> arr = np.arange(6) >>> np.split(arr, 2) [array([0, 1, 2]), array([3, 4, 5])] >>> print(type(np.split(arr, 2))) <class 'list'> >>> np.split(arr, 4) ValueError: array split does not result in an equal division >>> arr2 = np.arange(12).reshape(4, 3) >>> arr2 array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]]) >>> np.split(arr2, 3, axis=1) [array([[0], [3], [6], [9]]), array([[ 1], [ 4], [ 7], [10]]), array([[ 2], [ 5], [ 8], [11]])] arr3 = np.arange(12).reshape(6, 2) arr3 array([[ 0, 1], [ 2, 3], [ 4, 5], [ 6, 7], [ 8, 9], [10, 11]]) # [[:2], [2:3], [3:3], [3:]] np.split(arr2, (2, 3, 3)) [array([[0, 1], [2, 3]]), array([[4, 5]]), array([], shape=(0, 2), dtype=int64), array([[ 6, 7], [ 8, 9], [10, 11]])]
numpy.hsplit(ary, indices_or_sections)
Horizental,axis=1
인 numpy.split
과 동일하다.
numpy.vsplit(ary, indices_or_sections)
Vertical, axis=0
인 numpy.split
과 동일하다.
numpy.stack(arrays, axis=0, out=None)
>>> x = np.array([1, 2, 3]) >>> y = np.array([4, 5, 6]) >>> np.stack((x, y)) array([[1, 2, 3], [4, 5, 6]]) >>> np.stack((x, y), axis=1) array([[1, 4], [2, 5], [3, 6]])
numpy.hstack(tup)
>>> x = np.array([1, 2, 3]) >>> y = np.array([4, 5, 6]) >>> np.hstack((x, y)) array([1, 2, 3, 4, 5, 6])
numpy.vstack(tup)
>>> x = np.array([1, 2, 3]) >>> y = np.array([4, 5, 6]) >>> np.vstack((x, y)) array([[1, 2, 3], [4, 5, 6]])
numpy.dstack(tup)
x축을 기준으로 3차원으로 array를 합친다.
>>> x = np.array([1, 2, 3]) >>> y = np.array([4, 5, 6]) >>> np.dstack((x, y)) array([[[1, 4], [2, 5], [3, 6]]]) >>> x = np.arange(1, 7).reshape(2, 3) >>> y = np.arange(11, 17).reshape(2, 3) >>> x, y (array([[1, 2, 3], [4, 5, 6]]), array([[11, 12, 13], [14, 15, 16]])) >>> np.dstack((x, y)) # (2, 3) -> (2, 3, 2) array([[[ 1, 11], [ 2, 12], [ 3, 13]], [[ 4, 14], [ 5, 15], [ 6, 16]]])
numpy.concatenate((a1, a2, ...), axis=0, out=None, dtype=None, casting="same_kind")
axis 방향으로 array를 연결한다. stack
이 하나의 차원을 더해 그 안에 array를 합치는 반면, concatenate
는 기존의 차원에서 값을 연결한다. 즉 지정한 axis
가 2배가 된다.
>>> x = np.array([[[1, 2], [10, 20]], [[5, 6], [50, 60]]]) >>> y = np.array([[[3, 4], [30, 40]], [[7, 8], [70, 80]]]) >>> np.stack((x, y)) array([[[[ 1, 2], [10, 20]], [[ 5, 6], [50, 60]]], [[[ 3, 4], [30, 40]], [[ 7, 8], [70, 80]]]]) >>> np.stack((x, y)).shape (2, 2, 2, 2) >>> np.concatenate((x, y)) array([[[ 1, 2], [10, 20]], [[ 5, 6], [50, 60]], [[ 3, 4], [30, 40]], [[ 7, 8], [70, 80]]]) >>> np.concatenate((x, y)).shape (4, 2, 2) >>> np.concatenate((x, y), axis = 1) array([[[ 1, 2], [10, 20], [ 3, 4], [30, 40]], [[ 5, 6], [50, 60], [ 7, 8], [70, 80]]]) >>> np.concatenate((x, y), axis = 1).shape (2, 4, 2) >>> np.concatenate((x, y), axis = 2) array([[[ 1, 2, 3, 4], [10, 20, 30, 40]], [[ 5, 6, 7, 8], [50, 60, 70, 80]]]) >>> np.concatenate((x, y), axis = 2).shape (2, 2, 4)
transpose(a, axes=None)
축을 이동한다. 즉 배열 또는 행렬의 모양을 변경한다.
>>> arr = np.arange(6).reshape(2, 3) >>> arr array([[0, 1, 2], [3, 4, 5]]) >>> arr.transpose() array([[0, 3], [1, 4], [2, 5]]) >>>
>>> arr = np.array([[[ 1, 3, 5, 7], [ 2, 4, 6, 8]], [[ 10, 30, 50, 70], [ 20, 40, 60, 80]], [[ 100, 300, 500, 700], [ 200, 400, 600, 800]]]) >>> arr.shape (3, 2, 4) # z(3) -> x(axis=2) # y(2) -> z(axis=0) # x(4) -> y(axis=1) >>> np.transpose(arr, (1, 2, 0)) array([[[ 1, 10, 100], [ 3, 30, 300], [ 5, 50, 500], [ 7, 70, 700]], [[ 2, 20, 200], [ 4, 40, 400], [ 6, 60, 600], [ 8, 80, 800]]]) >>> np.transpose(arr, (1, 2, 0)).shape (2, 4, 3)
property matrix.T
attribute ndarray.T
축을 서로 바꾼다. 즉 배열 또는 행렬의 모양을 뒤집는다. 예컨대 (2, 3, 4)를 transposed하면 (4, 3, 2)로 바뀐다.
>>> arr = np.arange(6).reshape(2, 3) >>> arr array([[0, 1, 2], [3, 4, 5]]) >>> arr.shape (2, 3) # 1행이 1열로, 2행이 2열로 바뀜 >>> arr_t = arr.T >>> arr_t array([[0, 3], [1, 4], [2, 5]]) >>> arr_t.shape (3, 2)
ndarray.flatten(order='C')
n차원 배열을 1차원으로 변경한다.
>>> a = np.array([[1,2], [3,4]]) >>> a.flatten() array([1, 2, 3, 4]) >>> a.flatten('F') array([1, 3, 2, 4])
(method) astype: (dtype: DTypeLike, order: _OrderKACF = ..., casting: _Casting = ..., subok: bool = ..., copy: bool = ...) -> ndarray
원소의 자료형(Data type)을 dtype
으로 변경한다.
>>> arr = np.array([0.1, 2, 3]) >>> arr = arr.astype(int) >>> arr array([0, 2, 3]) >>> arr.dtype dtype('int64')
asarray(a, dtype=None, order=None, *, like=None)[source]
array로 변환할 수 있는(array like) object를 array로 변경한다.
>>> lis = range(5) >>> print(type(lis)) <class 'range'> >>> print(type(np.asarray(lis))) <class 'numpy.ndarray'>
asfarray(a, dtype=<class 'numpy.double'>)
array로 변환할 수 있는(array like) object를 C언어에서 double 자료형인dtype=float64
인 array로 변경한다.
>>> lis = range(5) >>> np.double numpy.float64 >>> print(np.asfarray(lis)) [0. 1. 2. 3. 4.] >>> print(np.asfarray(lis).dtype) float64 >>> print(type(np.asarray(lis))) <class 'numpy.ndarray'>
해당 부분을 이해하기 전 Pythons Copy에 대해 숙지한다.
=
을 사용해 동일한 주소값을 참조하는 object를 단순 복사한다.
>>> arr = np.array([1, 3, 5, 7, 9]) >>> arr_copy = arr >>> arr_copy[4] = 999 >>> print(arr) >>> print(arr_copy) [ 1 3 5 7 999] [ 1 3 5 7 999]
object a
의 array를 Shallow copy하여 반환한다. 그런데 array에서 shallow copy는 복합 객체에서도 단순 복사처럼 값이 변경된다.
>>> arr = np.array([1, 3, 5, 7, 9]) >>> arr_copy = arr.view() >>> arr_copy[4] = 999 >>> print(arr) >>> print(arr_copy) [ 1 3 5 7 999] [ 1 3 5 7 999]
copy(a, order='K', subok=False)
object a
의 array를 Deep copy하여 반환한다.
>>> arr = np.array([1, 3, 5, 7, 9]) >>> arr_copy = np.copy(arr) >>> arr_copy[4] = 999 >>> print(arr) >>> print(arr_copy) [1 3 5 7 9] [ 1 3 5 7 999]
원소의 자료형(Data type)을 반환한다.
(property) dtype: _DType
>>> arr = np.array([0.1, 2, 3]) >>> arr.dtype dtype('float64')
차원의 집합을 반환한다.
>>> arr = np.arange(24).reshape(3, 2, 4) >>> arr.shape (3, 2, 4)
(property) ndim: int
n-dimension, 배열의 차원을 반환한다.
>>> arr = np.arange(24).reshape(3, 2, 4) >>> arr.ndim 3
(property) size: int
>>> arr = np.arange(24).reshape(3, 2, 4) >>> arr.size 24
(property) itemsize: int
>>> arr = np.arange(24).reshape(3, 2, 4) >>> arr.itemsize 8
ndarray.strides
각 axis 별로 다음 데이터로 가기 위해 필요한 공간의 크기를 bytes로 반환한다.
>>> arr = np.arange(24).reshape(3, 2, 4) >>> arr 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]]]) >>> arr.dtype dtype('int64') >>> arr.strides (64, 32, 8)
위의 예는 z = 3
, y = 2
, x = 4
인 3D array다. data type은 int64로 8bytes(64bits)이다.
따라서 x에 해당하는 값 하나(0
, 1
, 2
...)는 8bytes의 값을 가진다. 즉 [0][0][0]
에서 [0][0][1]
로 이동하기 위해서는 8bytes를 이동하면 된다.
같은 논리로 y에 해당하는 값 하나([ 0, 1, 2, 3]
, [ 4, 5, 6, 7]
...)는 32bytes의 값을 가진다. 즉 [0][0][0]
에서 [0][1][0]
로 이동하기 위해서는 32bytes를 이동하면 된다. 또 z에 해당하는 값 하나는 64bytes의 값을 가진다. 즉 [0][0][0]
에서 [1][0][0]
로 이동하기 위해서는 64bytes를 이동하면 된다.
numpy.dot(a, b, out=None)
a와 b array를 행렬 곱셈 한다.
>>> arr = np.arange(4).reshape(2, 2) >>> arr array([[0, 1], [2, 3]]) >>> arr2 = np.arange(10, 18).reshape(2, 4) >>> arr2 array([[10, 11, 12, 13], [14, 15, 16, 17]]) >>> arr3 = np.zeros((2, 4), dtype="int") >>> arr3 array([[0, 0, 0, 0], [0, 0, 0, 0]]) >>> np.dot(arr, arr2, arr3) array([[14, 15, 16, 17], [62, 67, 72, 77]]) >>> arr3 array([[14, 15, 16, 17], [62, 67, 72, 77]])
Universal functions(범용 함수), 계산에 활용되며 broadcasting, reduce(축소), accumulate(축적) 등을 제공한다. Numpy에서 vectorization의 도구로 사용한다.
vectorization은 반복적인 문장을 vector에 기반한 연산으로 변환하는 것을 의미한다.
numpy.add(x1, x2, /, out=None, *, where=True, casting='same_kind', order='K', dtype=None, subok=True[, signature, extobj]) = <ufunc 'add'>
element-wise로 더한다.
>>> np.add(1, 10) 11 >>> np.add([1, 2, 3], [10, 20, 30] array([11, 22, 33]) >>> np.add(np.array([1, 2, 3]), np.array([10, 20, 30])) array([11, 22, 33])
set_printoptions(precision=None, threshold=None, edgeitems=None, linewidth=None, suppress=None, nanstr=None, infstr=None, formatter=None, sign=None, floatmode=None, *, legacy=None)
numpy.sort(a, axis=- 1, kind=None, order=None)[source]
정렬된 행렬을 반환한다. 원래 행렬이 가진 원소의 순서는 바뀌지 않는다.
ndarray.sort(axis=- 1, kind=None, order=None)
행렬을 정렬시키며, 반환값은 없다.
numpy.argsort(a, axis=- 1, kind=None, order=None)
정렬 전 행렬의 index를 정렬 된 순서로 반환한다.
>>> ar = np.array([9, 4, 1, 99]) # ar[0] = 9 # ar[1] = 4 # ar[2] = 1 # ar[3] = 99 >>> np.argsort(ar) [2 1 0 3] # [1, 4, 9, 99]로 정렬된 숫자의 원본 Index를 반환한다.