넘파이 배열
Numpy는 파이썬 내장 모듈이 아닙니다. 따라서 별도의 설치를 요구합니다. 하지만 아나콘다 환경 사용시 기본적으로 Numpy 패키지를 설치없이 사용할 수 있습니다.
- 숫자 데이터를 좀 더 쉽고 편리하게 다룰 수 있게 도와주는 패키지
- 숫자 데이터를 효과적으로 다룰 수 있기 때문에, 데이터 과학 및 데이터 분석에 많이 사용되는 파이썬 패키지
- Numpy는 다차원 배열 자료구조 클래스인, ndarray 클래스를 지원하며, 벡터와 행렬을 사용하는 선형대수 계산에 주로 사용
- import numpy as np
리스트가 아닌 넘파이 배열을 사용하는 이유
- 구조적으로 속도가 빠르고, 메모리를 더 적게 사용한다.(같은 종류의 데이터만 저장하기 때문에)
Numpy Array VS Python List
Numpy
- Numpy에 있는 값은 데이터 type 고정
- 메모리가 고정이 되어 있음
- 따라서 메모리 상에서 크기만큼만 건너 뛰면 값을 금방 추출할 수 있음
- LIst*
- 리스트는 삭제, 수정 때문에 메모리를 많이 차지하고 있고 메모리마다 연결을 지어놨고
- 길이, 순서 또한 메모리에 저장하고 있음(주소)
수많은 숫자 데이터를 하나의 리스트 시퀀스로 다루게 되면, 넘파이 배열에 비하여 상대적으로 속도가 느리고 메모리를 많이 차지하는 단점이 있습니다. 넘파이 패키지 배열을 사용하면 리스트에 비해 적은 메모리로 많은 데이터를 빠르게 처리할 수 있습니다. 다만 넘파이 배열은 많은 데이터를 다룰 수 있다는 점에서 리스트와 비슷하지만 이런 차이점을 갖습니다.
- 모든 요소(itmes)가 같은 자료형(type)이어야 합니다.(리스트는 다양한 자료형으르 섞어서 요소로 가질 수 있었습니다.
- 요소의 개수를 바꿀 수 없습니다.(리스트는 요소의 추가 및 삭제가 자유롭습니다)
리스트 자료형은 요소의 종류에 관계없이, 또 개수에 제한 없이 삽입, 삭제, 수정할 수 있었습니다.
그러 파이썬 배열 객체는 C언어 배열처림 메모리에서 연속적인 배치를 이루기 때문에 모든 요소가 같은 자료형이여야하고,
개수가 명확해야합니다.넘파이의 배열 연산넘파이의 배열 연산은 C로 구현된 내부 반복문을 사용하기 때문에 파이썬 반복문에 비해 속도가 빠르며 벡터화 연산(vectorized operation)을 이용하여 간단한 코드로도 복잡한 선형대수 연산을 수행할 수 있습니다. 또한 배열 인덱싱을 사용한 질의(Query) 기능을 이용하여 간단한 코드로로 간단한 코드로도 복잡한 수식을 계산할 수 있습니다.
-> 메모리 상에서 한칸씩 밀어버리거나, 몇칸 건너 뛰는 방식으로 훨씬 간단하게 계산 가능
넘파이 패키지 임포트하기
배열을 사용하기 위해 우선 다음과 같이 Numpy 패키지를 임포트 합니다. 별칭으로 np를 쓰는 것이 관례입니다.
Numy 패키지 이포트 - import numpy s npimport numpy s np'
너파이 배열 객체인 ndarray는 N-dimentinoal의 약자입니다. 1차원 배열, 2차원 배열,3 차원 배열 등의 다차원 병렬구조를 지원합니다
넘파이 arr의 array 메서드 인수로 시퀀스, ndaraay, 클래스 개체, 즉 넘파이 배열로 변환에
1ckdnjs qoduf aksemfrl
1차원 배열 만들기
type(arr)
ar = np.array([_ for _ in range(10))
ar2 = np.array(0.1, 5, 4, 12, 0.5)
array가 아무리 같은 자료형이라지만, 다른 것이 있을 때 표현범위가 더 큰 자료형으로 반환한다.
넘파이의 자료형
첫번 째 넘파이 배열에서 'f'를 활용하여 float로 dtype을 지정해줬습니다.
x = np.array([1,2,3], dtype = 'f')
x.dtype
dtype의 속성을 활용해 타입을 확인하니 32비트의 float형으로 생성된 것을 확인할 수 있습니다.
이 타입간 덧셈 연산(+)의 결과는 숫자로 계산됨을 확인함을 확인할 수 있습니다.
x[0] + x[1]
바로 아래 넘파이 배열에서는 유니코드 문자열 타입으로 지정해서 생성하였습니다.
x = np.array([1,2,3], dtype = 'U')
x.dtype
# 결과 'U'
1글자 이하의 글자들로 구성된 유니코드임을 추가적으로 설명하고 있습니다.
유니코드 간 덧셈 연산은 concatenate의 결과를 보여줍니다.
넘파이의 자료형2
- np.inf(infinity) : 무한대
- np.nan(not a number) : 정의 할 수 없는 숫자
다음 예와 같이 1과 0으로 나누려고 하거나 0에 대한 로그 값을 계산하면 무한대인 np.inf가 나옵니다.
0을 0으로 나누려고 시도하면 np.nan이 나옵니다. np.log(0) # inf np.exp(-np.inf) # 0.0
벡터화 연산(Vectorized Operation)
넘파이 배열 객체는 배열의 각 요소에 대한 반복 연산을 하나의 명령어로 처리하는 벡터화 연산을 지원합니다.
예를 들어 다음처럼 리스트 내 모든 요소 데이터를 모두 2배해야하는 경우를 생각해봅시다.
data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
answer = [2 * d for d in data]
print(answer)
넘파이 배열 객체의 벡터화 연산을 사용하면 다음과 같이 한번의 연산식으로 표현할 수 있습니다.
물론 계산속도도 리스트 객체에 반복문을 사용해서 처리하는 것보다 훨씬 빠릅니다.
x = np.array(data)
2 * x
벡터화 연산 - 리스트와의 차이
리스트의 곱하기
list_samp = [_ for _ in range(3)]
print(list_samp * 5)
# 결과값
# [0,1,2][0,1,2][0,1,2][0,1,2][0,1,2]
벡터화 연산은 비교 연산과 논리 연산을 포함한 모든 종류의 수학 연산에 대해 적용됩니다.
a = np.array([1,2,3])
b = np.array([10,20,30])
print(2 * a + b)
# array([12,24,36])
print(a == 2)
# array([False, True, False])
print(b > 10)
# array([False, True, True])
print((a == 2) & (b > 10))
# array([False, True, False))
2차원 배열 만들기
2차원 배열은 수학에서 행렬(matrix)이라고 했었습니다.
행렬에서는 가로줄 행(row)이라고 하고 세로줄을 열(column)이라고 부릅니다.
이와 비슷한 구조를 넘파이 배열을 통해 만들어보겠습니다.
c = np.array([[1,2,3],[4,5,6]]) # 2 x 3 array
print(c.shape) # (2,3)
print(c)
# 행의 개수
len(c)
# 열의 개수
len(c[0])
3차원 배열 만들기
3차원 배열은 깊이 x 행 x 열의 모양을 갖습니다.
아래 그래픽을 보면 axis 0이 깊이를 의미하고 axis 1이 행을, axis 2가 열을 표현하는 축임을 알 수 있습니다.
@그림대체
리스트의 리스트의 리스트를 이용하면 3차원 배열도 생성할 수 있습니다.
크기를 나타낼 때는 가장 바깥쪽 리스트의 길이의 순서로 표시합니다.
예를 들어 2 x 3 x 4 배열은 다음과 같이 만듭니다.
- 3차원 배열의 깊이(len(d))
- 3차원 배열의 행(len(d[0])
- 3차원 배열의 열(len(d[0][0])
배열의 차원과 크기 알아내기
배열의 차원 및 크기를 구하는 더 간단한 방법은 배열의 ndim 속성과 shape 속성을 이용하는 것입니다.
ndim 속성은 배열의 차원, shape 속성은 배열의 크기를 반환합니다.
# a = np.array(\[1,2,3\])
print(a.ndim) # 1
print(a.shape) # (3,)
# c = np.array(\[0,1,2\],\[3,4,5\])
print(c.ndim) # 2
print(c.shape) # 2,3
배열의 인덱싱
다차원 배열일 때는 다음과 같이 콤마(comma,)를 사용하여 접근할 수 있습니다.
콤마로 구분된 차원을 축(axis)이라고도 합니다. 그래프의 x축과 y축을 떠올리면 됩니다.
list_sample = [[0,1,2],[3,4,5]]
list_sample[0][0]
list_sample[-1][-1]
배열의 슬라이싱
배열 객체로 구현한 다차원 배열의 원소 중 복수 개를 접근하려면 일반적인
파이썬 슬라이싱(slicing)과 comma(,)를 함께 사용하면 됩니다.
list_sample = [[0,1,2],[3,4,5]]
list_sample[0, :] # 첫번째 행 전체
list_sample[:, 1] # 두번째 열 전체
list_sample[1, 1:] # 두번째 행의 두번째 열부터 끝 열까지
list_sample[:2, :2] # [[0,1][3,4]]
.reshape(행,열)
np.array([1,2,3,4,5,6,7,8,9,10]).reshape(2,5)
배열 생성
Numpy는 몇가지 단순한 배열을 생성하는 메서드를 제공합니다.
a = np.zeros(5)
# [0.,0.,0.,0.,0.]
a = np.zeros(5, dtype = 'i')
# [0,0,0,0,0]
# 문자열 배열도 가능하지만 원소의 크기가 같아야합니다.
만약 더 큰 크기의 문자열을 할당하면 잘릴 수 있습니다.
d = np.zeros(5, dtype = '<U4')
0이 아닌 1로 초기화된 배열을 생성하려면 ones 명령을 사용합니다.
e = np.ones((2,3,4), dtype = "i8")
e
만약 크기를 튜플로 명시하지 않고 다른 배열과 같은 크기의 배열을 생성하고 싶다면
ones_like, zero_like 명령을 사용합니다.
f = np.ones_like(b, dtype = 'f')
배열의 크기가 커지면 배열을 초기화하는데도 시간이 걸립니다.
이 시간을 단축하려면 배열을 생성만 하고 특정한 값으로 초기화 하지 않는 empty 명령을 사용할 수 있습니다.
empty 명령으로 생성된 배열에는 기존에 메모리에 저장되어 있던 값이 있으므로 배열의 원소의 값을 미리 알 수 있습니다.
range 명령은 Numpy 버전의 range 명령이라고 볼 수 있다. 특정한 규칙에 따라 증가하는 수열을 만듭니다.
np.arange(10)
np.arange(3, 21, 2) # 시작, 끝(포함하지 않음), 단계
np.liinespace(시작, 끝, 간격)
print(np.linesapce(0,100, 5))
# array[ 0., 25., 50., 75., 100.]
전치연산
2차원 배열의 전치(transpose) 연산은 행과 열을 바꾸는 작업입니다. 이는 배열의 T 속성으로 구할 수 있습니다.
메서드가 아닌 속성이라는 점에 유의합시다.
A = np.array([[1,2,3],[4,5,6]])
A.T
배열의 크기 변형
다차원 배열을 1차원으로 만들기 위해서는 flatten 혹은 ravel 메서드를 사용합니다.
a.flatten()
b.ravel()
배열 연결
행의 수나 열의 수가 같은 두개 이상의 배열을 연결하여(concatenate) 더 큰 배열을 만들 때는 다음과 같은 명령을 사용합니다.
- hstack
- vstack
- dstack
- stack
- r_
- c_
- tile
벡터화 연산의 차이
x = np.arange(1,10001)
y = np.arrange(10001, 20001)
%%time
z = x + y
## 43 밀리초
# for문 사용 구현시 10.1 마이크로초
# 엄청난 속도 차이
사칙 연산 뿐만 아니라 비교 연산과 같은 논리연산도 벡터화 연산이 가능합니다.
a = np.array([1,2,3,4])
b = np.array([4,2,2,4])
a == b
all 명령
만약 배열의 원소들을 일일히 비교하는 것이 아니라, 배열의 모든 원소가 다 같은지 알고 싶다면
all 명령을 사용하면 됩니다.
a = np.array([1,2,3,4])
b = np.array([4,2,2,4])
np.all(a == b)
스칼라와 벡터/행렬의 곱셈
넘파이 배열에서 스칼라와 벡터/행렬의 곱도 선형대수에서 사용하는 식과 같이 표현 가능합니다.
x = np.arange(10)
10 * x
x = np.arange(12).reshape(3,4)
100 * x
브로드캐스팅
보통 배열끼리 산술연산을 하려면 아래의 예제처럼 두 배열의 shapes가 정확히 같아야 합니다.
a = np.array([1.0, 2.0, 3.0])
b = np.array([2.0, 2.0, 2.0])
하지만 넘파이 배열은 모양이 다른 배열간의 연산이 가능하도록 배열의 크기를 변환시켜주는
브로드캐스팅(broadcasting)을 지원합니다.
넘파이가 처리하는 브로드캐스팅의 방법은 더 작은 배열이 더 큰 배열에 호환되는 모양으로
확장하는 식으로 진행됩니다.
100 * a
@그림대체 - 배열과 스칼라 값이 연산될 때의 개념 그림(stretch)
@ 배열간의 곱 vs 스칼라곱의 메모리 효율성
-> 스칼라로 되어 있는 것이 더 적은 메모리를 이동한다.
넘파이 배열은 모양이 다른 배열 간의 연산이 가능하도록 배열의 크기를 변환시켜주는
브로드캐스팅(broadcasting)을 지원한다고 하는데, 과연 모든 경우에 가능한걸까요?
아닙니다. 확장이 가능한 경우가 있고 불가능한 경우도 존재합니다.
- 확장 가능한 규칙
- 넘파이 배열의 shape을 우측 정렬하고 각 차원별로 숫자를 비교합니다. 비교하는 모든 차원이 두 조건 중 하나에 충족되어야 브로드 캐스팅 가능합니다.
- 해당 차원 간의 숫자가 동일한 경우(3 x 4 x 5 행렬, 4 x 1 행렬(가능) 3 x 2 x 7 행렬 / 3 x 2 행렬 (불가능))
- 해당 차원 중 하나가 1인 경우
@ 브로드캐스팅 가능한 경우 그림 대체
@ 브로드캐스팅 불가능한 경우
- 해당 차원 중 하나가 1인 경우
- 해당 차원 간의 숫자가 동일한 경우(3 x 4 x 5 행렬, 4 x 1 행렬(가능) 3 x 2 x 7 행렬 / 3 x 2 행렬 (불가능))
- 넘파이 배열의 shape을 우측 정렬하고 각 차원별로 숫자를 비교합니다. 비교하는 모든 차원이 두 조건 중 하나에 충족되어야 브로드 캐스팅 가능합니다.
차원축소연산
행렬의 하나의 행에 있는 원소들을 하나의 데이터 집합으로 보고, 그 집합의 평균을 구하면
각 행에 대해 하나의 숫자가 나오게 됩니다. 예를 들어 10 x 5 크기의 2차원 배열에 대해 행-평균을 구하면
10개의 숫자를 가진 1차원의 벡터가 나오게 됩니다. 이러한 연산을 차원 축소(dimension reduction) 연산이라고 합니다.
넘파이는 다음과 같은 차원 축소 연산 명령 혹은 메서드를 지원합니다.
- 최대/최소 : min, max, argmin, argmax
- 통계 : sum, mean, median, std, var
- 불리언 : all, any
'데이터 분석 및 시각화 > 파이썬' 카테고리의 다른 글
[Python] 기초 정리(Pandas_DataFrame) (0) | 2023.01.18 |
---|---|
[Python] 기초 정리(Pandas_Series) (2) | 2023.01.18 |
[Python] 기초 정리(Class) (1) | 2023.01.13 |
[Python] 기초 정리(전역변수, 지역변수, 람다(lambda)) (0) | 2023.01.13 |
[Python] 기초 정리(함수, 문자열 메서드 join) (0) | 2023.01.12 |