Python

[Python] numpy

SangRok Jung 2022. 9. 22. 12:32
반응형

numpy


  • 파이썬에서 수치 해석을 위한 배열을 사용하는 표준 패키지입니다.
  • 다차원 배열의 자료구조 클래스인 ndarray 클래스를 지원하며 벡터와 행렬을 사용하는 선형대수 계산에 주로 사용됩니다.
  • 내부적으로 BLAS 라이브러리와 LAPACK 라이브러리를 사용하고 있으며 C로 구성된 CPython에서만 사용할 수 있습니다.
  • 넘파이의 배열 연산은 C로 구현된 내부 반복문을 사용하기 때문에 파이썬 반복문에 비해 속도가 빠르며 벡터화 연산을 이용하여 간단한 코드로도 복잡한 선형 대수 연산을 수행 할 수 있습니다.
  • 배열 인덱싱을 사용한 질의 기능을 이용하여 간단한 코드로도 복잡합 수식을 계산할 수 있습니다.

 

 

 

▶ 리스트의 단점

  • 많은 숫자 데이터를 하나의 변수에 넣고 관리할 때 속도가 느리며 메모리를 많이 차지 합니다.

 

이 리스트의 단점을 Array(배열)를 사용함으로써 해결할 수 있습니다.

 

 

▶ Array

  • 모든 원소가 같은 자료형이어야 합니다.
  • 원소의 갯수를 바꿀 수 없습니다.

 

 

▶ 넘파이 텐서 연산의 장점

  • C와 유사한 형태로 메모리를 관리하면서 C와 같은 연산속도로 계산할 수 있습니다.
    • 메모리 구조상 요소들이 붙어 있기 때문입니다.
    • 파이썬의 가장 큰 특징인 동적 타이핑을 포기했지만, C로 구현되어 있어 배열 연산에 있어 매우 큰 성능적 우위를 확보합니다.
    • 대용량 배열 연산에서 넘파이가 사실상 표준으로 사용됩니다.
    • 연결 연산처럼 여러 배열을 붙이는 연산에서는 일반적인 리스트에 비해 느립니다.
      • 메모리 탐색과정으로 새로운 공간을 잡아야 하기 때문입니다.

 

 

 

 

 

ndarray & tensor


▶ ndarray(넘파이 배열) 

  • 넘파이에서 텐서 데이터를 다루는 객체

▶ 텐서(tensor) 

  • 선형대수의 데이터 배열
    • 랭크(rank)에 따라 이름이 다릅니다.

 

 

 

 

 

 

 

Python List와 Numpy Array의 차이점


▶ 텐서 구조에 따라 Array를 생성합니다.

  • 배열의 모든 구성 요소에 값이 존재해야 합니다.
  • 동적 타이핑을 지원하지 않습니다.
    • 하나의 데이터 타입만 사용합니다.
  • 데이터를 메모리에 연속적으로 나열합니다.
    • 각 값의 메모리 크기가 동일합니다.
    • 검색이나 연산 속도가 리스트에 비해 훨씬 빠릅니다.

 

 

 

 

 

 

 

numpy 패키지 import


import numpy as np

 

 

 

 

 

numpy Array 생성


▶ 생성

test_array = np.array([1, 4, 5, '8'], float)

print(test_array)
print(type(test_array[3]))
print(test_array.dtype) # 전체 데이터 타입 반환
print(test_array.shape) # 배열의 shape(구조)를 반환, (n차원)로 출력됩니다.

# [1. 4. 5. 8.]
# <class 'numpy.float64'>
# float64
# (4,)

 

 

 

float32 데이터 타입인 넘파이 배열의 각 값을 저장하는 메모리 블록은 4byte씩 차지 합니다.

 

 

 

 

 

 

 

numpy Array shape(구조)


▶ 2랭크의 배열 구조

matrix = [[1, 2, 5, 8], [1, 2, 5, 8], [1, 2, 5, 8]]

np.array(matrix, int).shape
# (3, 4)

 

 

 

 

 

 

 

 

▶ 3랭크의 배열 구조

matrix = [[[1, 2, 5, 8], [1, 2, 5, 8], [1, 2, 5, 8]],
         [[1, 2, 5, 8], [1, 2, 5, 8], [1, 2, 5, 8]],
         [[1, 2, 5, 8], [1, 2, 5, 8], [1, 2, 5, 8]]]

print(np.array(matrix, int).shape)
print(np.array(matrix, int).ndim) #number of dimension
print(np.array(matrix, int).size) 
# (3, 3, 4)
# 3
# 36

 

 

 

 

 

 

 

 

 

 

 

dtype


np.array의 매개변수로 numpy array의 데이터 타입을 지정합니다.

  • 변수가 사용하는 데이터 타입의 메모리 크기가 정해집니다.

 

np.array([[1, 2, 3.5], [4, 5, 6.5]], dtype = int)

# array([[1, 2, 3],
#        [4, 5, 6]])
np.array([[1, 2, 3.5], [4, 5, 6.5]], dtype = float)

# array([[1. , 2. , 3.5],
#        [4. , 5. , 6.5]])

 

▶ itemsize

  • 배열 각 맴버의 바이트 크기를 리턴합니다.
import sys
np.array([[1, 2, 3.5], [4, 5, 6.5]], dtype = np.float32).itemsize
# 4
# byte가 생략됨
import sys
np.array([[1, 2, 3.5], [4, 5, 6.5]], dtype = np.float64).itemsize
# 8
# byte가 생략됨

※ Int = 4byte, float = 8byte

 

 

 

 

 

 

 

 

 

reshape()


  • 배열의 구조를 변경하고 랭크를 조절합니다.
  • 차원 인자 값에 -1을 입력하면 전체 요소의 개수를 고려하여 마지막 차원이 자동으로 지정됩니다.

 

 

▶ 기본 문법

변경할 배열.reshape(변경할 차원)

np.reshape(변경할 배열, 변경할 차원)

 

x = np.array([[1, 2, 5, 8], [1, 2, 5, 8]])
x.reshape(-1,)

# array([1, 2, 5, 8, 1, 2, 5, 8])
x = np.array([[1, 2, 5, 8], [1, 2, 5, 8]])
x.reshape(2, 2, 2)

# array([[[1, 2],
#         [5, 8]],
# 
#        [[1, 2],
#         [5, 8]]])
x = np.array(range(8))

x.reshape(2, -1)

# array([[0, 1, 2, 3],
#        [4, 5, 6, 7]])

 

 

 

 

 

 

 

 

flatten()


  • 데이터의 개수는 그대로 존재합니다
  • 배열의 구조만 변합니다.

 

 

x = np.array.(range(8)).reshape(2, 2, 2)
x.flatten()

# array([0, 1, 2, 3, 4, 5, 6, 7])

 

 

 

 

 

 

 

 

 

Indexing & Slicing


▶ Indexing

  • 리스트에 있는 값의 상대적인 offset(주소)로 값에 접근합니다.
  • 넘파이 배열의 인덱스 표현에는 ','을 지원합니다.
    • [a][b] 또는 [a,b] 형태
  • 3차원 텐서 이상은 shape에서 출력되는 랭크 순서대로 인덱싱에 접근합니다.

 

x = np.array([[1, 2, 3], [4, 5, 6]], int)
print(x[0][2])
print(x[0,2])
# 3
# 3

 

 

 

 

▶ slicing

  • 인덱스를 사용하여 리스트 일부를 잘라내어 반환합니다.
  • 넘파이 배열은 행과 열을 나누어 슬라이싱 할 수 있습니다.

x = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]], int)

print(x[:,2:])
# [[ 3  4  5]
#  [ 8  9 10]]

print(x[1, 1:3])
# [7 8]

print(x[1:3])
# [[ 6  7  8  9 10]]

 

 

 

 

 

 

 

 

 

 

Step


  • 리스트에서 데이터의 요소를 호출 할 때 데이터를 건너 뛰면서 반환합니다.
    • [시작 인덱스 : 마지막 인덱스 : 증가값]
    • 각 랭크에 있는 요소별로 모두 적용 할 수 있습니다.

 

x = np.array(range(15), int).reshape(3, -1)

print(x)
# [[ 0  1  2  3  4]
#  [ 5  6  7  8  9]
#  [10 11 12 13 14]]

붉은 값만 추출.

print(x[:,::2])

# [[ 0  2  4]
#  [ 5  7  9]
#  [10 12 14]]

print(x[::2,::3])

# [[ 0  3]
#  [10 13]]

 

 

 

 

 

 

 

 

 

 

arange


  • 배열을 생성하는 함수입니다.
  • ragne 함수와 같이 차례대로 값을 생성합니다.
  • range 함수와 달리 증가값에 실수형이 입력되어도 값을 생성 할 수 있습니다.
  • 소수점 값을 주기적으로 생성할 때 유용합니다.

 

▶ 구문

np.arange(시작 인덱스, 마지막 인덱스, 증가값);
print(np.arange(10))
print(np.arange(-5, 5))
print(np.arange(0, 5, 0.5))

# [0 1 2 3 4 5 6 7 8 9]
# [-5 -4 -3 -2 -1  0  1  2  3  4]
# [0.  0.5 1.  1.5 2.  2.5 3.  3.5 4.  4.5]

 

 

 

 

 

 

 

 

 

 

ones, zeros, empty


  • 배열을 생성합니다.
  • 생성 시점에 dtype을 지정해주면 해당 데이터 타입으로 배열을 생성합니다.

 

▶ ones

  • 1로만 구성된 넘파이 배열을 생성합니다.
    • 사전에 shape값을 넣어서 원하는 크기의 넘파이 배열을 생성합니다.

 

▶ zeros

  • 0으로만 구성된 넘파이 배열을 생성합니다.

 

▶ empty

  • 활용 가능한 메모리 공간을 확보하여 반환합니다.
  • ones와 zeros는 먼저 shape의 크기만큼 메모리를 할당하고 그곳에 값을 채웁니다.
  • 해당 메모리 공간에 값이 남았을 경우 그 값을 함께 반환합니다.
  • 생성될 때마다 다른 값을 반환합니다.

 

 

▶ 구문

print(np.ones(shape=[5, 2], dtype=np.int8))

# [[1 1]
#  [1 1]
#  [1 1]
#  [1 1]
#  [1 1]]

print(np.zeros(shape=[2, 2], dtype=np.float32))

# [[0. 0.]
#  [0. 0.]]

 

 

 

 

 

 

 

 

 

ones_like, zeros_like, empty_like


▶ ones_like

  • 기존 넘파이 배열과 같은 크기로 만들어 내용을 1로 채웁니다.

 

▶ zeros_like

  • 기존 넘파이 배열과 같은 크기로 만들어 내용을 0으로 채웁니다.

 

▶ empty_like

  • 기존 넘파이 배열과 같은 크기로 만들어 빈 상태로 만듭니다.

 

 

▷ 예문

x = np.arange(12).reshape(3, 4)

print(x)
#[[ 0  1  2  3]
# [ 4  5  6  7]
# [ 8  9 10 11]]

print(np.ones_like(x))
# [[1 1 1 1]
#  [1 1 1 1]
#  [1 1 1 1]]

print(np.zeros_like(x))
# [[0 0 0 0]
#  [0 0 0 0]
#  [0 0 0 0]]

print(np.empty_like(x))
# [[0 0 0 0]
#  [0 0 0 0]
#  [0 0 0 0]]

 

 

 

 

 

 

 

 

identity, eye, diag


▶ identity

  • 단위 행렬을 생성합니다.
    • 매개변수 n으로 n x n 단위 행렬을 생성합니다.

 

▷ 예문

print(np.identity(n=3, dtype=int))

# [[1 0 0]
#  [0 1 0]
#  [0 0 1]]

print(np.identity(n=4, dtype=int))

#[[1 0 0 0]
# [0 1 0 0]
# [0 0 1 0]
# [0 0 0 1]]

 

 

 

 

▶ eye

  • 시작점과 행렬 크기를 지정, 단위 행렬을 생성합니다.
    • N = 행의 개수, M = 열의 개수
    • k = 열의 값을 기준으로 시작하는 인덱스

 

▷ 예문

print(np.eye(N=3, M=5, k=2))

# [[0. 0. 1. 0. 0.]
#  [0. 0. 0. 1. 0.]
#  [0. 0. 0. 0. 1.]]

 

 

 

 

 

▶ diag

  • 행렬의 대각선분 값을 추출합니다.

 

▷ 예문

 

print(np.diag(np.arange(9).reshape(3, 3)))
# [0 4 8]

print(np.diag(np.arange(9).reshape(3, 3), k=1))
# [1 5]

 

 

 

 

 

 

 

 

 

통계 분석 함수


▶ uniform()

  • 균등분포 함수

 

▷ 구문

np.uniform(시작값, 끝값, 데이터 개수)

 

▷ 예문

print(np.random.uniform(0, 5, 10))

# [0.52675772 0.42216318 3.88471858 2.38202763 3.23275871 2.58250078
#  3.81355672 4.66374263 1.46639956 3.29314779]

 

 

 

 

▶ normal()

  • 정규분포 함수

 

▷ 구문

np.normal(평균값, 분산, 데이터 개수)

 

▷ 예문

print(np.random.normal(0, 2, 10))
# [ 1.67769499  2.65559914 -0.83006297 -0.54458485  1.96107166  1.43042317
#  -1.4927319  -1.8952236  -0.91212602  0.83006339]
x = np.random.normal(0, 2, 10)
print(np.mean(x)) # 평균
print(np.std(x)) # 표준편차
print(np.var(x)) # 분산
# 0.37585327103539473
# 1.1455876931248066
# 4.6868580082283
x = np.random.normal(0, 2, 100000)
print(np.mean(x)) # 평균
print(np.std(x)) # 표준편차
# 0.007768645296492016
# 1.9900835518846567

 

 

 

 

 

 

 

 

 

연산 함수


▶ sum()

  • 배열 내부 연산을 지원하는 함수
  • 배열의 랭크가 증가 할 때마다 새로운 축이 추가되어 차원이 증가됩니다.

 

▷ axis

  • 배열의 랭크가 증가할 때마다 새로운 축이 추가되어 차원이 증가됩니다.

 

 

 

▶ 랭크 1의 연산.

test_array = np.arange(1, 11)
test_array.sum()
# 55

 

 

 

 

 

 

 

▶ 랭크 2의 연산.

print(np.arange(1, 13).reshape(3, 4).sum(axis = None))
# 78

print(np.arange(1, 13).reshape(3, 4).sum(axis = 0)) # 컬럼 별로 더한다.
# [15 18 21 24]

print(np.arange(1, 13).reshape(3, 4).sum(axis = 1)) # 로우 별로 더한다.
# [10 26 42]

 

 

 

▶ 랭크 3의 연산.

# 3차원 합


print(third_order_tensor.sum(axis = 1))
# [[15 18 21 24]
#  [15 18 21 24]
#  [15 18 21 24]]


print(third_order_tensor.sum(axis = 0))
# [[ 3  6  9 12]
#  [15 18 21 24]
#  [27 30 33 36]]


print(third_order_tensor.sum(axis = 2))
# [[10 26 42]
#  [10 26 42]
#  [10 26 42]]
# print(test_array)
print(test_array.mean(axis = 1))
print(test_array.std(axis = 0))
print(np.sqrt(test_array))

# [ 2.5  6.5 10.5]
# [3.26598632 3.26598632 3.26598632 3.26598632]
# [[1.         1.41421356 1.73205081 2.        ]
#  [2.23606798 2.44948974 2.64575131 2.82842712]
#  [3.

 

 

 

 

 

 

 

 

 

연결 함수


 

  • 두 객체 간의 결합을 지원하는 함수

 

▶ vastck 함수

  • 배열을 수직으로 붙여 하나의 행렬을 생성합니다.

 

▶hstack 함수

  • 배열을 수평으로 붙여 하나의 행렬을 생성합니다.

 

v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])

np.vstack((v1, v2))
# ([[1, 2, 3],
#   [4, 5, 6]])

np.hstack((v1, v2))
# ([1, 2, 3, 4, 5, 6])

v1 = v1.reshape(-1, 1)
v2 = v2.reshape(-1, 1)

np.hstack((v1, v2))
# ([[1, 4],
#   [2, 5],
#   [3, 6]])

 

 

 

▶ concatenate 함수 (연결 함수)

  • 축을 고려하여 두 개의 배열을 결합합니다.
  • stack(스택) 계열의 함수와 달리 생성될 배열과 소스가 되는 배열의 차원이 같아야 합니다.
  • 두 벡터를 결합한다면 해당 벡터를 2차원 배열꼴로 변환 한 후 행렬로 나타내야 합니다.

 

▷ 2랭크 연결

v1 = np.array([[1, 2, 3]])
v2 = np.array([[4, 5, 6]])


print(np.concatenate((v1, v2)))
# [[1 2 3]
#  [4 5 6]]

 

▷ 2랭크 axis = 1 연결

v1 = np.array([[1, 2], [3, 4]])
v2 = np.array([[5], [6]])

print(np.concatenate((v1, v2), axis=1))
# [[1 2 5]
#  [3 4 6]]

 

 

 

 

 

 

 

사칙연산 함수


  • 넘파이는 파이썬과 동일하게 배열 간 사칙연산을 지원합니다.
    • 행렬과 행렬, 벡터와 벡터 간 사칙연산이 가능합니다.
  • 같은 배열의 구조일 때 요소별 연산(elemetn-wise operation)
    • 요소별 연산 : 두 배열의 구조가 동일 할 경우 같은 인덱스 요소들끼리 연산합니다.

 

▷ 예문

x = np.arange(1, 7).reshape(2, 3)

print(x + x)
# [[ 2  4  6]
#  [ 8 10 12]]

print(x - x)
# [[0 0 0]
#  [0 0 0]]

print(x / x)
# [[1. 1. 1.]
#  [1. 1. 1.]]

print(x ** x)
# [[    1     4    27]
#  [  256  3125 46656]]

반응형

'Python' 카테고리의 다른 글

[Python] 파일 저장  (0) 2022.09.27
[Python] numpy 내적연산  (1) 2022.09.24
[Python] Anaconda 가상환경 생성  (0) 2022.09.21
[Python] CRAWLING - Element Access  (0) 2022.09.16
[Python] CRAWLING - BeautifulSoup  (0) 2022.09.13