Numpy - ndarray

  • Numpy : 선행대수 기반 프로그램을 쉽게 만들 수 있는 패키지
  • 루프 없이 대량의 데이터 배열 연산을 빠르게 처리
  • 2차원 행과 열의 데이터는 판다스가 더 유용
  • 기본 데이터 타입 : ndarray
In [1]:
# pip install numpy
In [2]:
# np : 관례적인 nimpy 별명
import numpy as np
In [3]:
# 파이썬의 list 값을 ndarray로 변환
array1 = np.array([1, 2, 3])
print('array1 type:', type(array1))
print('array1 array 형태:', array1.shape) # (3,) : 3행 배열을 의미 

array2 = np.array([[1, 2, 3],
                  [2, 3, 4]])
print('array2 type:', type(array2))
print('array2 array 형태:', array2.shape) # (2, 3) : 2행, 3열 배열을 의미 

array3 = np.array([[1, 2, 3]])
print('array3 type:', type(array3))
print('array3 array 형태:', array3.shape) # (1, 3) : 1행 3열 배열을 의미 
array1 type: <class 'numpy.ndarray'>
array1 array 형태: (3,)
array2 type: <class 'numpy.ndarray'>
array2 array 형태: (2, 3)
array3 type: <class 'numpy.ndarray'>
array3 array 형태: (1, 3)
In [4]:
# 차원 확인 : ndim
print('array1: {:0}차원, array2: {:1}차원, array3: {:2}차원'.format(array1.ndim, array2.ndim, array3.ndim))
array1: 1차원, array2: 2차원, array3:  2차원
In [5]:
list1 = [1, 2, 3]
print(type(list1))
array1 = np.array(list1)
print(type(array1))
print(array1, array1.dtype)
<class 'list'>
<class 'numpy.ndarray'>
[1 2 3] int32
In [6]:
list2 = [1, 2, 'test']
array2 = np.array(list2)
print(array2, array2.dtype)
['1' '2' 'test'] <U11
In [7]:
list3 = [1, 2, 3.0]
array3 = np.array(list3)
print(array3, array3.dtype)
[1. 2. 3.] float64

ndarray를 편리하게 생성하기 - arange, zeros, ones¶

  • ndarray를 연속값이나 0 또는 1로 초기화해서 생성
  • 테스트용 데이터나 대규모 데이터 일괄 초기화해야 할 경우 사용
In [8]:
# 파이썬의 range()
seq_array = np.arange(10)
print(seq_array)
print(seq_array.dtype, seq_array.shape)
[0 1 2 3 4 5 6 7 8 9]
int32 (10,)
In [9]:
# 0으로 초기화
zero_array = np.zeros((3, 2), dtype='int32')
print(zero_array)
print(zero_array.dtype, zero_array.shape)
[[0 0]
 [0 0]
 [0 0]]
int32 (3, 2)
In [10]:
# 1. dmfh chrlghk
one_array = np.ones((3, 2))
print(one_array)
print(one_array.dtype, one_array.shape)
[[1. 1.]
 [1. 1.]
 [1. 1.]]
float64 (3, 2)

reshape()

  • ndarray를 특정 차원 및 크기로 변환
  • ex. 1차원을 2차원 2x5로 변환
In [11]:
array1 = np.arange(10)
print('array1:\n', array1)

array2 = array1.reshape(2, 5)
print('array2:\n', array2)

array3 = array1.reshape(5, 2)
print('array3:\n', array3)
array1:
 [0 1 2 3 4 5 6 7 8 9]
array2:
 [[0 1 2 3 4]
 [5 6 7 8 9]]
array3:
 [[0 1]
 [2 3]
 [4 5]
 [6 7]
 [8 9]]
In [12]:
# 10개로 만들 수 없는 사이즈는 오류 발생
# array4 = array1.reshape(4, 3) # 4,3 은 12개의 데이터가 필요
In [13]:
# -1 사용 시 가능한 개수를 자동으로 생성
array1 = np.arange(10)
print(array1)

array2 = array1.reshape(-1, 5)
print("array2 shape:", array2.shape)

array3 = array1.reshape(5, -1)
print('array3 shape:', array3.shape)
[0 1 2 3 4 5 6 7 8 9]
array2 shape: (2, 5)
array3 shape: (5, 2)
In [14]:
# -1을 사용해도 불가능한 사이즈는 오류 발생
array1 = np.arange(10)
# array4 = array1.reshape(-1, 4)
In [15]:
array1 = np.arange(8)
array3d = array1.reshape((2, 2, 2)) # 3차원
                         #a, b, c     b x c 가 a개 있는 행렬
print('array3d: \n', array3d.tolist())

# 3차원 ndarray를 2차원 ndarray롭 변환
array5 = array3d.reshape(-1, 1)
print('array5: \n', array5.tolist())
print('array5 shape:', array5.shape)


# 1차원 ndarray를 2차원 ndarray로 변환
array6 = array1.reshape(-1, 1)
print('array6: \n', array6.tolist())
print('array56 shape:', array6.shape)
array3d: 
 [[[0, 1], [2, 3]], [[4, 5], [6, 7]]]
array5: 
 [[0], [1], [2], [3], [4], [5], [6], [7]]
array5 shape: (8, 1)
array6: 
 [[0], [1], [2], [3], [4], [5], [6], [7]]
array56 shape: (8, 1)

indexing

  • 단일값 추출
In [16]:
# 1부터 9까지의 1차원 ndarray 생성
array1 = np.arange(start=1, stop=10)
print('array1', array1)

# index는 0부터 시작하기에 array1[2]는 세 번째 index 위치의 데이터 값을 의미 = 3
value = array1[2]
print('value:', value)
print(type(value))
array1 [1 2 3 4 5 6 7 8 9]
value: 3
<class 'numpy.int32'>
In [17]:
print('맨 뒤의 값:', array1[-1])
print('맨 뒤에서 두번째 값:', array1[-2])
맨 뒤의 값: 9
맨 뒤에서 두번째 값: 8
In [18]:
# 값 치환
array1[0] = 9
array1[8] = 0
print('array1:', array1)
array1: [9 2 3 4 5 6 7 8 0]
In [19]:
# 2차원
array1d = np.arange(start=1, stop=10)
array2d = array1d.reshape(3, 3)
print(array2d)

print('(row=0, col=0) index 가리키는 값', array2d[0, 0])
print('(row=0, col=1) index 가리키는 값', array2d[0, 1])
print('(row=1, col=0) index 가리키는 값', array2d[1, 0])
print('(row=2, col=2) index 가리키는 값', array2d[2, 2])
[[1 2 3]
 [4 5 6]
 [7 8 9]]
(row=0, col=0) index 가리키는 값 1
(row=0, col=1) index 가리키는 값 2
(row=1, col=0) index 가리키는 값 4
(row=2, col=2) index 가리키는 값 9

slicing

In [20]:
array1 = np.arange(start=1, stop=10)
array3 = array1[0:3]
print(array3)
print(type(array3))
[1 2 3]
<class 'numpy.ndarray'>
In [21]:
array4 = array1[:3]
print(array4)

array5 = array1[3:]
print(array5)

# 값 복사
array6 = array1[:]
print(array6)
[1 2 3]
[4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9]
In [22]:
array1d = np.arange(start=1, stop=10)
array2d = array1d.reshape(3,3)
print('array2d:\n', array2d)
print('array2d[0:2, 0:2]: \n', array2d[0:2, 0:2])
print('array2d[1:3, 0:3]: \n', array2d[1:3, 0:3])
print('array2d[1:3, :] \n', array2d[1:3, :])
print('array2d[:, :] \n', array2d[:, :])
print('array2d[:2, 1:] \n', array2d[:2, 1:])
print('array2d[:2, 0] \n', array2d[:2, 0])
array2d:
 [[1 2 3]
 [4 5 6]
 [7 8 9]]
array2d[0:2, 0:2]: 
 [[1 2]
 [4 5]]
array2d[1:3, 0:3]: 
 [[4 5 6]
 [7 8 9]]
array2d[1:3, :] 
 [[4 5 6]
 [7 8 9]]
array2d[:, :] 
 [[1 2 3]
 [4 5 6]
 [7 8 9]]
array2d[:2, 1:] 
 [[2 3]
 [5 6]]
array2d[:2, 0] 
 [1 4]

fancy indexing

  • 일정한 인덱싱 집합을 리스트 또는 ndarray 형태로 지정해 해당 위치에 있는 데이터의 ndarray를 반환
In [23]:
array1d = np.arange(start=1, stop=10)
array2d = array1d.reshape(3,3)
print('array2d:', array2d.tolist())
array3 = array2d[[0,1], 2]
print('array2d([0,1], 2):', array3.tolist())
array4 = array2d[[0,1], 0:2]
print('array2d([0,1], 0:2):', array4.tolist())
array5 = array2d[[0,1]]
print('array2d([0,1]):', array5.tolist())
array2d: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
array2d([0,1], 2): [3, 6]
array2d([0,1], 0:2): [[1, 2], [4, 5]]
array2d([0,1]): [[1, 2, 3], [4, 5, 6]]

boolean indexing

  • 조건 필터링과 검색을 동시에 사용
In [24]:
array1d = np.arange(start=1, stop=10)
array3 = array1d[array1d > 5]
print('array1d > 5 boolean 인덱싱 값 결과:', array3)
array1d > 5 boolean 인덱싱 값 결과: [6 7 8 9]
In [25]:
array1d > 5
Out[25]:
array([False, False, False, False, False,  True,  True,  True,  True])
In [26]:
boolean_indexes = np.array([False, False, False, False, False,  True,  True,  True,  True])
array3 = array1d[boolean_indexes]
print('boolean 인덱스 필터링 결과:', array3)
boolean 인덱스 필터링 결과: [6 7 8 9]
In [27]:
indexes = np.array([5, 6, 7, 8])
array4 = array1d[indexes]
print('일반 인덱스 필터링 결과:', array4)
일반 인덱스 필터링 결과: [6 7 8 9]

행렬의 정렬

  • sort()
  • argsort() : 정렬된 행렬의 인덱스 반환
In [28]:
org_array = np.array([3, 1, 9, 5])
print('원본:', org_array)
원본: [3 1 9 5]
In [29]:
# np.sort() 정렬
sort_array1 = np.sort(org_array)
print('np.sort() 호출 후 반환된 정렬 행렬:', sort_array1)
print('np.sort() 호출 후 원본 행렬:', org_array)
np.sort() 호출 후 반환된 정렬 행렬: [1 3 5 9]
np.sort() 호출 후 원본 행렬: [3 1 9 5]
In [30]:
# ndarray.sort() 정렬 : 리턴 값이 반환되지 않고 기존 원본 행렬을 정렬
sort_array2 = org_array.sort()
print('org_array.sort() 호출 후 반환된 정렬 행렬:', sort_array2)
print('org_array.sort() 호출 후 원본 행렬:', org_array)
org_array.sort() 호출 후 반환된 정렬 행렬: None
org_array.sort() 호출 후 원본 행렬: [1 3 5 9]
In [31]:
# 내림차순
org_array = np.array([3, 1, 9, 5])
sort_array1_desc = np.sort(org_array)[::1]
print('내리차순으로 정렬:', sort_array1_desc)
내리차순으로 정렬: [1 3 5 9]
In [32]:
array2d = np.array([[8, 12],
                   [7, 1]])
print('기본:\n', array2d)

sort_array2d_axis0 = np.sort(array2d, axis=0) # axis=0 : 로우(행) 방향
print('로우 방향으로 정렬:\n', sort_array2d_axis0)

sort_array2d_axis1 = np.sort(array2d, axis=1) # axis=1 : 칼럼(열) 방향
print('칼럼 방향으로 정렬:\n', sort_array2d_axis1)
기본:
 [[ 8 12]
 [ 7  1]]
로우 방향으로 정렬:
 [[ 7  1]
 [ 8 12]]
칼럼 방향으로 정렬:
 [[ 8 12]
 [ 1  7]]
In [33]:
# argsort
# 정렬 행렬의 인덱스(위치)를 반환
org_array = np.array([3, 1, 9, 5])
sort_indices = np.argsort(org_array)
print(type(sort_indices))
print('행렬 정렬 시 원본 행렬의 인덱스:', sort_indices)
<class 'numpy.ndarray'>
행렬 정렬 시 원본 행렬의 인덱스: [1 0 3 2]
In [34]:
# 내림차순
org_array = np.array([3, 1, 9, 5])
sort_indices_desc = np.argsort(org_array)[::-1]
print('행렬 내림차순 정렬 시 원본 행렬의 인덱스:', sort_indices_desc)
행렬 내림차순 정렬 시 원본 행렬의 인덱스: [2 3 0 1]
In [35]:
name_array = np.array(['John', 'Mike', 'Sarah', 'Kate', 'Samuel'])
score_array = np.array([78, 95, 84, 98, 88])

# 성적을 오름차순으로 인덱스 정렬
sort_indices_asc = np.argsort(score_array) 
print('성적 오름차순 정렬 시 score_array의 인덱스 :', sort_indices_asc)
# 정렬한 인덱스를 기반으로 이름 출력 : 성적이 낮은 학생 순서로 정렬해서 출력
print('성적 오름차순으로 name_array의 이름 출력 : ', name_array[sort_indices_asc])          
성적 오름차순 정렬 시 score_array의 인덱스 : [0 2 4 1 3]
성적 오름차순으로 name_array의 이름 출력 :  ['John' 'Sarah' 'Samuel' 'Mike' 'Kate']

선형대수 연산 - 행렬 내적과 전치 행렬 구하기

In [36]:
# 행렬 내적 - np.dot()
A = np.array([[1, 2, 3],
              [4, 5, 6]])
B = np.array([[7, 8],
              [9, 10],
              [11, 12]])

dot_product = np.dot(A, B)
print('행렬 내적 결과:\n', dot_product)
# 1*7 + 2*9 + 3*11 = 56    1*8 + 2*10 + 3*12 = 64      [[58 64]
# 4*7 + 5*9 + 6*11 = 138   4*8 + 5*10 + 6*12 = 154    [139 154]]
행렬 내적 결과:
 [[ 58  64]
 [139 154]]
In [37]:
# 전치행렬 transpose() : 원행렬에서 행과 열의 위치를 교환
A = np.array([[1, 2],
              [3, 4]])
transpose_mat = np.transpose(A)
print('A의 전치 행렬:\n', transpose_mat)
A의 전치 행렬:
 [[1 3]
 [2 4]]
In [38]:
# 역행렬 np.linalg.lav() : 내적의 곱으로 단위행렬이 나오는 행렬
a = np.array(range(4)).reshape(2, 2) # 1차원 0부터 3까지의 데이터를 2차원으로 변환
a
Out[38]:
array([[0, 1],
       [2, 3]])
In [39]:
a_inv = np.linalg.inv(a)
a_inv
Out[39]:
array([[-1.5,  0.5],
       [ 1. ,  0. ]])
In [40]:
a.dot(a_inv)
Out[40]:
array([[1., 0.],
       [0., 1.]])