본문 바로가기
Python/데이터 분석

[Python] Numpy 심화

by snow_white 2022. 3. 17.

Numpy란?

  • Numerical Python 의 약자로 넘파이라 부르기도 함
  • 파이썬의 내장 타입인 리스트보다 데이터의 저장 및 처리에 있어 효율적인 Numpy 배열을 제공
  • 선형 대수와 관련된 기능을 제공
  • 파이썬 기반으로 한 데이터 과학 도구의 핵심 패키지

데이터 사이언스 영역의 대부분의 도구

(Pandas, Scipy 패키지, skikit-learn 패키지 등) Numpy 기반

 


Numpy의 주요 기능

 

Numpy 패키지와 배열(ndarray) 객체

  • array 함수 사용하여 동질의 데이터를 다룰 수 있는 구조 (빠르게 접근 가능)
  • 데이터 타입을 지정하여 구성할 수 있음
  • list comprehension[루프] 으로 원소를 만들 수 있음
  • 초기화 가능한 여러 가지 함수 제공
    • 1차원을 만드는 zeros
    • 1차원을 만들고 1로 채우는 ones
    • 초기값을 임의로 설정해서 채우는 full
    • 원소를 구성하는 배열 객체를 생성하는 np.arrange
    • 균등하게 interval을 구성할 수 있는 linspace
    • 데이터 모의 구성 시 많이 사용하는 random
    • 정규분포를 나타내는 normal
    • 명령어 행/열 변환 reshape
    • list와 list를 연결하는 concatenate
  • 랜덤 값의 재현성의 문제로 seed 함수에 seed값을 주면 재현성 문제를 해결할 수 있음

 

 

import numpy as np

print(np.array([1,4,2,5,3]))
print(np.array([1,2,3,4], dtype=np.float)) # 데이터 타입 지정
print(np.array([range(i, i+3) for i in [1,4,7]])) # list comprebension
print(np.zeros(10)) # 1차원으로 만듦
print(np.ones((3,5))) # 13행 5열로 만들고 1로 채움
print(np.full((2,3),5)) # 2행 3열을 초기값 5로 채움
print(np.arange(0,10,2)) # 배열 객체 생성 start, end, step 순
print(np.linspace(0,100,5, dtype=int)) # 5구간으로 나눠 0~100까지 배열 객체로 만듦
print(np.random.random(3,3)) # 3행 3열로 데이터를 0~1 사이 값으로 구성
print(np.random.randint(0,10,(3,3))) # 0~9까지의 수를 3행 3열로 구성
print(np.random.normal(0,1,(3,3))) # 평균 0, 표준편차 1의 랜덤수 3행 3열로 구성

'''
[1 4 2 5 3]
[1. 2. 3. 4.]
[[1 2 3]
 [4 5 6]
 [7 8 9]]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[[1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1.]
 [1. 1. 1. 1. 1.]]
[[5 5 5]
 [5 5 5]]
 '''

 

seed 값을 주어 랜덤 재현성 문제 해결하기

  • ndim : 차원 정보
  • shape : 행/열, 원소의 구조 정보, 원소의 개수와 차원 정보를 알 수 있음
  • size : 원소의 개수
  • dtype : data type
import numpy as np

np.random.seed(0) # 임의의 숫자를 넣어 매번 코드를 실행해도 동일한 결과 나옴

arr1 = np.random.randint(10, size=6) # 0~10 사이의 6개 정수
arr2 = np.random.randint(10, size=(2,3))

print("arr1:\n%s" % arr1)
print("ndim: %d, shape: %s, size: %d, dtype: %s\n" % (arr1.ndim, arr1.shape, arr1.size, arr1.dtype))
print("arr2:\n%s" % arr2)
print("ndim: %d, shape: %s, size: %d, dtype: %s" % (arr2.ndim, arr2.shape, arr2.size, arr2.dtype))

'''
arr1:
[5 0 3 3 7 9]
ndim: 1, shape: (6,), size: 6, dtype: int32

arr2:
[[3 5 2]
 [4 7 6]]
ndim: 2, shape: (2, 3), size: 6, dtype: int32
'''

 

Numpy의 다차원 배열을 인덱싱할 때는 arr[ i ][ j ] 형태가 아닌 arr[ i ,  j ] 형태로 사용합니다.

import numpy as np

np.random.seed(0) # 임의의 숫자를 넣어 매번 코드를 실행해도 동일한 결과 나옴

arr1 = np.random.randint(10, size=6) # 0~10 사이의 6개 정수
arr2 = np.random.randint(10, size=(2,3))

print(arr1) # [5 0 3 3 7 9]
print(arr1[0], arr1[5]) # 5 9
print(arr1[-6], arr1[-1]) # 5 9

print(arr2)
#[[3 5 2]
# [4 7 6]]
print(arr2[0, 0], arr2[0, 2]) # 3 6
print(arr2[-1, -3], arr2[-1, -1]) # 4 6

arr2[0, 0] = 9
print(arr2)
#[[9 5 2]
# [4 7 6]]

 

Numpy 배열 객체의 슬라이싱 [ start : end : step ]

import numpy as np

np.random.seed(0)

arr1 = np.arange(10)
print(arr1) # [0 1 2 3 4 5 6 7 8 9]

print(arr1[0:5:1]) # [0 1 2 3 4]
print(arr1[:5:1]) # [0 1 2 3 4]
print(arr1[:5:], arr1[:5]) # [0 1 2 3 4] [0 1 2 3 4]
print(arr1[2:9:2], arr1[2::2]) # [2 4 6 8] [2 4 6 8]
print(arr1[::-1]) # [9 8 7 6 5 4 3 2 1 0]
print(arr1[-1:-11:-1]) # [9 8 7 6 5 4 3 2 1 0]
print(arr1[5::-1]) # [5 4 3 2 1 0]

arr2 = np.arange(12).reshape(-1,4)
print(arr2, arr2[:3, :4], arr2[:, :])
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
'''
print(arr2[:2, :3])
'''
[[0 1 2]
 [4 5 6]]
'''
print(arr2[:2, 2::-1])
'''
[[2 1 0]
 [6 5 4]]
'''
print(arr2[1:, -1]) # [ 7 11]
print(arr2[-1, :], arr2[-1]) # [ 8  9 10 11] [ 8  9 10 11]

 

Numpy 배열 객체의 연결

 

※ 주의! list1과 list2를 [ ] 로 list 안에 담아 전달할 것

list1 = [1,2,3]
list2 = [4,5,6]
print(np.concatenate([list1, list2])) # [1 2 3 4 5 6]

arr2 = arr1.reshape(-1,3) # 6개의 요소를 2행 3열로 구성
print(arr2)
'''
[[1 2 3]
 [4 5 6]]
'''

arr1 = np.concatenate([list1, list2], axis=0) # 축 설정
print(arr1) # [1 2 3 4 5 6]

print(np.vstack([arr2, arr2])) # vertical stack 
print(np.concatenate([arr2, arr2], axis=1)) # 2차원 배열인 arr2를 가로축 방향으로 배열을 연결할 때 행방향으로!
'''
[[1 2 3 1 2 3]
 [4 5 6 4 5 6]]
'''
print(np.hstack([arr2, arr2])) # horizontal stack 
print(np.concatenate([arr2, arr2], axis=0)) # 2차원 배열인 arr2를 세로축 방향으로 배열을 연결할 때 열방향으로!
'''
[[1 2 3]
 [4 5 6]
 [1 2 3]
 [4 5 6]]
'''

 

Numpy 배열 객체의 내장 함수 사용

 

빠른 연산이 가능한 vectorize function(벡터화 함수)

import numpy as np

np.random.seed(0)

arr2 = np.random.randint(1,10,(3,4))
print(arr2)
'''
[[6 1 4 4]
 [8 4 6 3]
 [5 8 7 9]]
'''
print(np.sum(arr2), arr2.sum()) # 65 65 , axis가 none 인 경우로 모든 원소를 더함
print(np.sum(arr2, axis=0), arr2.sum(axis=0)) # [19 13 17 16] [19 13 17 16] , 세로(열) 방향으로 sum 정보 구성
print(np.sum(arr2, axis=1), arr2.sum(axis=1)) # [15 21 29] [15 21 29] , 가로(행) 방향으로 sum 정보 구성

print(np.min(arr2, axis=0), np.max(arr2, axis=0)) # [5 1 4 3] [8 8 7 9]
print(arr2.min(axis=0), arr2.max(axis=0)) # [5 1 4 3] [8 8 7 9]

print(np.min(arr2, axis=1), np.max(arr2, axis=1)) # [1 3 5] [6 8 9]
print(arr2.min(axis=1), arr2.max(axis=1)) # [1 3 5] [6 8 9]

 

 

브로드캐스팅

 

3행 2열짜리 배열과 다른 배열의 연산이 이루어질 때 행과 열의 정보가 일치해야 같은 위치끼리 연산이 가능합니다.

때문에, 전체 shape이 맞아야 하기 때문에 행열 구조를 동일하게 맞춰주는 브로드캐스팅 과정이 필수입니다.

import numpy as np

np.random.seed(0)

X = np.random.random((10, 3)) # 10 행, 3 열
print(X)
'''
[[0.5488135  0.71518937 0.60276338]
 [0.54488318 0.4236548  0.64589411]
 [0.43758721 0.891773   0.96366276]
 [0.38344152 0.79172504 0.52889492]
 [0.56804456 0.92559664 0.07103606]
 [0.0871293  0.0202184  0.83261985]
 [0.77815675 0.87001215 0.97861834]
 [0.79915856 0.46147936 0.78052918]
 [0.11827443 0.63992102 0.14335329]
 [0.94466892 0.52184832 0.41466194]]
 '''

Xmean = X.mean(axis=0) # 1행 , 3 열
print(Xmean)
'''
[0.52101579 0.62614181 0.59620338]
'''

Xcentered = X - Xmean # (10 행, 3 열)짜리 - (1행 , 3 열)짜리
print(Xcentered)
'''
[[ 0.02779771  0.08904756  0.00655999]
 [ 0.02386739 -0.20248701  0.04969073]
 [-0.08342858  0.26563119  0.36745938]
 [-0.13757427  0.16558323 -0.06730846]
 [ 0.04702877  0.29945483 -0.52516732]
 [-0.43388649 -0.60592341  0.23641646]
 [ 0.25714096  0.24387034  0.38241496]
 [ 0.27814277 -0.16466245  0.18432579]
 [-0.40274137  0.01377921 -0.45285009]
 [ 0.42365312 -0.10429349 -0.18154144]]
 '''

 

 

부울 배열과 마스킹 연산

 

부울값을 가진 배열에서 만족하는 데이터를 찾아내는 연산입니다.

import numpy as np

np.random.seed(0)

X = np.random.randint(1, 10, size=(3,4))
print(X)

print((X>5) & (X<8)) # 해당 조건을 만족하면 True, 아니면 False

print(np.sum((X>5) & (X<8))) # 3 , True가 나오는 지점을 모두 더함

print(np.sum((X>5) | (X<8))) # 12

print(np.sum((X>5) & (X<8), axis=0)) # [1 0 2 0] 열 방향으로 더함
 
print(np.sum((X>5) & (X<8), axis=1)) # [1 1 1] 행 방향으로 더함

print(X[(X>5) & (X<8)]) # [6 6 7] 조건에 해당하는 부울 배열을 전달해 만족하는 데이터 꺼냄

 

 

팬시 인덱싱

 

인덱스를 담고 있는 배열을 전달해서 인덱스 배열을 만족하는 부분집합을 추출하는 방법입니다.

reshape를 이용해 구조를 변환해도 동일한 결과를 냅니다.

import numpy as np

np.random.seed(0)

X = np.arange(12).reshape((3,4))
print(X)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
'''

row = np.array([0,1,2])
col = np.array([1,2,3])
print(X[row])
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
'''

print(X[:, col]) # X에 col 전달
'''
[[ 1  2  3]
 [ 5  6  7]
 [ 9 10 11]]
'''

print(X[row, col]) # [ 1  6 11]  X에 row, col 전달

print(X[row.reshape(-1,1), col])
'''
[[ 1  2  3]
 [ 5  6  7]
 [ 9 10 11]]
'''

 

복합 인덱싱

X = np.zeros(12).reshape((3,4)) # 인덱싱
X
'''
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
'''

X[0,1] = 1
X
'''
array([[0., 1., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
'''

X[1,[1,3]] = 2 # 팬시 인덱싱, 2번째 열과 4번째 열에 1을 넣음
X
'''
array([[0., 1., 0., 0.],
       [0., 2., 0., 2.],
       [0., 0., 0., 0.]])
'''

X[[0,2], [1,3]] = 2 # 팬시 인덱싱 + 슬라이싱
X
'''
array([[0., 2., 0., 0.],
       [0., 2., 0., 2.],
       [0., 0., 0., 2.]])
'''

X[0:3, [0,2]] = 3 # 팬시 인덱싱 + 슬라이싱 = 범위 집합 추출
X
'''
array([[3., 2., 3., 0.],
       [3., 2., 3., 2.],
       [3., 0., 3., 2.]])
'''

 

Numpy 배열 객체의 정렬

np.random.seed(0)

x = np.array(np.random.randint(10, size=5))
x  # array([5, 0, 3, 3, 7])

np.sort(x)  # array([0, 3, 3, 5, 7])

x  # array([5, 0, 3, 3, 7])

x.sort()
x     # array([0, 3, 3, 5, 7])

np.random.seed(0)
x = np.array(np.random.randint(10, size=5))
x  # array([5, 0, 3, 3, 7])

idx = np.argsort(x)  # sort된 인덱스를 전달하는 함수
idx  # array([1, 2, 3, 0, 4], dtype=int64)

x[idx]   # array([0, 3, 3, 5, 7])  팬시 인덱싱을 통해 정렬 가능

'Python > 데이터 분석' 카테고리의 다른 글

[Numpy] Numpy 배열의 정렬  (0) 2022.04.02
[Numpy] Numpy 배열의 Indexing & Slicing  (0) 2022.04.02
[Numpy] Numpy 배열의 연산  (0) 2022.04.02
[Numpy] Numpy 배열의 속성 및 함수  (0) 2022.04.02
[Numpy] Numpy  (0) 2022.04.02

댓글