목차
-
넘파이(numpy) 배열
-
넘파이 배열 생성
-
넘파이 배열의 속성(필드)
-
넘파이 배열의 연산 : 브로드 캐스팅
-
리스트와 넘파이 배열 + 연산의 차이
-
넘파이 배열 곱셈 연산자 : *와 @
-
실습 . BMI 계산
-
넘파이 배열 인덱싱과 슬라이싱
-
2차원 배열 인덱싱
-
2차원 배열 슬라이싱
-
논리 인덱싱(Logical indexing)
-
2차원 배열 논리 인덱싱
-
실습) 2차원 배열에서 조건 만족 행 추출
-
넘파이 배열 생성 : zeros(), ones() , eye()
-
넘파이 배열 생성 함수 : arange()
-
넘파이 배열 생성 함수 : linspace(), logspace()
-
넘파이 배열의 형태 변경 메소드
-
난수 배열 생성
-
정규분포 난수 배열 생성
-
난수 관련 함수
-
넘파이 배열의 속성 : T
-
넘파이 배열 평균 계산
-
넘파이 unique() 함수
-
넘파이 배열 합치기
-
넘파이 배열 분리
-
기타 넘파이 함수
넘파이(numpy) 배열
- 리스트처럼 여러 개의 값들을 저장할 수 있는 자료구조
- 리스트는 다양한 자료형의 데이터 저장 가능
- 넘파이 배열은 같은 자료형의 데이터 저장
- 리스트보다 데이터 처리속도가 빠름
- 리스트는 데이터 접근을 위해 이중 참조 ⇒ 해당 이유 때문에 리스트의 처리속도가 느림
- 리스트는 객체 배열
- 넘파이 배열은 한번의 참조로 데이터 접근 가능
- 리스트는 데이터 접근을 위해 이중 참조 ⇒ 해당 이유 때문에 리스트의 처리속도가 느림
- 대량의 데이터를 빠르게 처리하려면 넘파이 배열 필요
- 데이터 과학, 인공지능 분야에서 넘파이 배열 사용
- 넘파이 배열은 ndarray 클래스로 구현
- ndarray 클래스 장점
- C언어에 기반한 배열 구조이므로 메모리를 적게 차지하고 속도가 빠르다.
- 배열과 배열 간에 수학적인 연산을 적용
- 배열의 모든 원소 적용되는 연산자 함수 제공
- 행렬 연산
- 고급 연산자와 풍부한 함수 제공
- 브로드 캐스팅
- 인덱싱
- 슬라이싱
- 논리적 인덱싱
- 난수 배열
- 다차원 배열 표현 가능
- 1차원 배열 → 인덱스 1개 → arr[j] (열)
- 2차원 배열 → 인덱스 2개 ⇒ arr[i][j] == arr[i, j] (행, 열)
- 3차원 배열 → 인덱스 3개 → arr[k][i][j] == arr[k, i, j] (면, 행, 열)
- 배열의 차원을 축(axis) 이라 함
넘파이 배열 생성
- 넘파이를 사용하기위해 넘파이 패키지 불러옴
- ex) import numpy
- 넘파일 모듈이름을 간략히 표현하기 위해 별칭 부여
- ex) import numpy as np
- 넘파이 배열 생성자
- array( ) 함수
- 초기값 전달을 위해 생성자에 리스트(배열, range객체) 전달
- ex) arr = np.array([1,2,3]) → arr는 배열이름 ( 참조변수 )
- array( ) 함수
넘파이 배열의 속성(필드)
- ndarray 클래스의 속성(필드)
- ndim → 배열의 차원
- shape → 배열의 형태 : 튜플로 표현
- ex) (3, ) → 3열의 1차원 배열
- ex) (2, 3) → 2행, 3열의 2차원 배열
- ex) (4, 2, 3) → 4면, 2행, 3열의 3차원 배열
- dtype → 원소의 타입
- itemsize → 원소의 할당크기
- ex) int32 → 4바이트
- size → 배열 전체 크기(원소의 총 개수)
# 넘파이 배열의 속성(필드)
import numpy as np
arr1 = np.array([1, 2, 3])
print(arr1)
print(arr1.ndim, arr1.shape, arr1.dtype, arr1.itemsize, arr1.size, '\n')
arr2 = np.array([[1,2,3], [4, 5, 6]])
print(arr2)
print(arr2.ndim, arr2.shape, arr2.dtype, arr2.itemsize, arr2.size, '\n')
arr3 = np.array([[[1,1,1], [2,2,2]], [[3,3,3], [4,4,4]]])
print(arr3)
print(arr3.ndim, arr3.shape, arr3.dtype, arr3.itemsize, arr3.size, '\n')
넘파이 배열의 연산 : 브로드 캐스팅
- ndarray 클래스의 연산자 함수
- 형식 → 넘파이배열 산술연산자(op) 값(v)
- 넘파이 배열의 모든 원소에 값과 산술연산 적용한 배열 반환
- ex) arr1 + 3 → 배열의 모든 원소에 +3을 적용한 배열 반환
- ex) arr1 ** 2 → 배열의 모든 원소에 **2를 적용한 배열 반환
- 형식 → 넘파이배열 산술연산자(op) 값(v)
리스트와 넘파이 배열 + 연산의 차이
- 넘파이 배열 + 넘파이 배열 : 벡터화 연산(원소별 덧셈)
- 넘파이 배열의 +연산자는 배열 원소별 덧셈 연산자
- 리스트 + 리스트 = 두개의 리스트가 연결됨
# 리스트와 넘파이 배열 + 연산의 차이
import numpy as np
lst1 = [1, 2, 3]
lst2 = [4, 5, 6]
print(lst1 + lst2) # 리스트 + 연산자 ==> 리스트 연결 연산자
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
print(arr1 + arr2) # 넘파이배열 + 연산자 ==> 원소별 덧셈 연산자
#시험에 나올수 있음.
# 넘파이 배열은 print 시 쉼표가 없음!!!!!!!
넘파이 배열 곱셈 연산자 : *와 @
- 넘파이 배열 * 넘파이 배열 → 벡터화 연산(원소별 곱셈)
- 넘파이 배열 @ 넘파이 배열 → 행렬 곱셈
- (p, q) 배열 @ (q, r) 배열 → (p, r) 배열 반환
실습 . BMI 계산
- n명 키와 몸무메가 주어졌을 때, 넘파이 배열을 이용하여 n명의 BMI를 일괄 처리
# 실습. bmi 계산
import numpy as np
h = [1.83, 1.75, 1.71, 1.85, 1.77, 1.73]
w = [80, 74, 59, 90, 77, 78]
harr = np.array(h)
warr = np.array(w)
bmi = warr/harr**2
- 넘파이 배열을 사용함으로써 for문을 안써서 코드 작성시간이 획기적으로 줄여질수 있다
넘파이 배열 인덱싱과 슬라이싱
- 넘파이 배열도 리스트처럼 인덱싱과 슬라이싱 지원
- 인덱싱 → 특정 요소를 추출(정수 인덱싱)
- arr[i] → i번째 원소 반환
- 첫번째 원소의 인덱스 = 0
- arr[i] → i번째 원소 반환
- 음수 인덱스 –i → 뒤에서 i번째 원소 반환
- arr[-1] == arr[n-1] ← n의 배열의 크기
- cf) 넘파이 배열의 인덱싱 : 정수 인덱싱, 배열 인덱싱, 논리 인덱싱
- 인덱싱 → 특정 요소를 추출(정수 인덱싱)
- 슬라이싱 → 특정 요소 집합을 추출
- arr[ s : e ] → arr[s]에서 arr[e-1] 사이의 원소 집합의 배열 반환
- 시작 인덱스와 종료 인덱스 생략 가능
- arr[ : e ] → arr[0]에서 arr[e-1] 사이의 원소 집합의 배열 반환
- arr[ s : ] → arr[s]에서 arr[n-1] 사이의 원소 집합의 배열 반환
- arr[ : ] → 배열의 모든 원소 집합의 배열 반환
- arr[ : ] == arr[0: ] == arr[ :n] == arr[0:n] ← n은 배열의 크기
- arr[ s : e ] → arr[s]에서 arr[e-1] 사이의 원소 집합의 배열 반환
넘파이는 모든 배열의 타입이 같아야한다.
리스트는 다양한 타입이 저장이 가능한데 그 이유는 참조주소만 참조하기때문에 가능하다. 그래서 속도도 느리다.
2차원 배열 인덱싱
- 2차원 배열의 2가지 인덱싱 방법
- arr[i][j] == arr[i,j]
- i행, j열의 원소 반환
- arr[i] → i행 원소 집합(1차원 배열) 반환
- arr[i][j] == arr[i,j]
import numpy as np
arr = np.array([[1,2,3], [4,5,6]])
print(arr[0]) # 0행의 원소 집합(1차원 배열) 반환
print(arr[0][1], arr[0,1]) # 0행, 1열의 원소 반환
print(arr[-1][-1], arr[-1, -1]) # 마지막 행, 열의 원소 반환
arr[0,0] = 7.7 # 배열arr는 정수배열로 생성되었다 -> 실수 입력시 정수로 타입 변환된다.
print(arr)
2차원 배열 슬라이싱
- 2차원 배열 슬라이싱 방법
- arr[sr:er][sc:ec] == arr[sr:er, sc:ec]
- sr행~(er-1)행, sc열~(ec-1) 열 사이의 원소 집합을 배열로 반환
- 슬라이싱 범위를 나타내는 인덱스 생략 가능
- 시작 인덱스 생략 → 0, 끝 인덱스 생략 → n(행/열의 크기)
- 2차원 배열 슬라이싱 반환 값의 차원
- arr[범위, 인덱스], arr[인덱스, 범위] → 1차원 배열 반환
- arr[범위, 범위] → 2차원 배열 반환
- 슬라이싱 범위 형식
- 시작인덱스 : 끝 인덱스 : 인덱스간격
- ex) arr[0, 0:n:2] → 0행, 짝수 인덱스열(0, 2, 4, …) 1차원 배열 반환
- 시작인덱스 : 끝 인덱스 : 인덱스간격
# 2차원 배열 슬라이싱
import numpy as np
arr = np.array([[1,2,3], [4,5,6]])
print(arr[0, :]) # 1차원 배열
print(arr[0:1, :]) # 2차원 배열 만약 0:2 하면 다음 열의 값도 나옴
# [0: ,:] 하면 모든 행, 열 출력
print(arr[0, ::2]) # 짝수인덱스열 1차원 배열
논리 인덱싱(Logical indexing)
- 논리데이터 배열(논리 배열)을 인덱스로 사용
- 배열과 인덱스로 사용할 논리배열은 같은 크기(shape 동일)
- 논리배열의 원소가 참(True)인 인덱스에 해당되는 배열의 원소들만 추출
- 반환 배열의 크기 = 논리배열의 참인 원소의 수
- cf) 배열 인덱싱 → 인덱스배열로 인덱싱 : 해당 인덱스 원소만 추출
- 논리배열 생성
- 넘파이 배열에 논리 연산 적용(브로드캐스팅)
- • ex) arr > 0 → 양인 원소는 True, 다른 원소는 False인 논리배열 반환
- 장점 : 반복문을 쓰지 않고 필터링을 할 수 있다.
- 넘파이 배열에 논리 연산 적용(브로드캐스팅)
# 논리 인덱싱
arr = np.array([1,2,3,4,5])
print(arr[ [0, 2, 4] ]) # 배열 인덱싱 => 짝수 인덱스에 위치한 원소만 추출 : 1차원 배열 반환
larr = arr >= 3 # 논리 배열 생성 : 배열에 논리 연산 적용
print(larr)
print(arr[larr]) # 논리 인덱싱 => 1차원 배열 반환
2차원 배열 논리 인덱싱
- 논리배열이 2차원 배열일 때
- 2차원 배열과 같은 shape의 논리배열 필요
- 2차원 배열에 논리 연산 적용(브로드캐스팅)
- arr[2차원_논리배열] → 1차원 배열 반환
- 논리배열의 참인 원소의 인덱스에 위치한 배열의 원소들만 추출
- 2차원 배열과 같은 shape의 논리배열 필요
# 2차원 배열 논리 인덱싱
import numpy as np
arr = np.array([[1,2,3], [4,5,6]])
larr = arr % 2 == 0 # 짝수인 원소만 True 2차원 논리배열 생성
print(larr)
print(arr[larr]) # 논리 인덱싱 => 1차원 배열 반환
- 논리배열이 1차원 배열일 때
- 2차원 배열의 행의 크기와 같은 1차원 논리배열 필요
- 2차원 배열 슬라이싱(열 추출) 후 논리연산 → 1차원 논리배열 생성
- ex) arr[:, 0] % 2 == 0 → 0열 배열(1차원 배열)에 논리 연산 적용
- arr[1차원_논리배열] → 2차원 배열 반환
- 논리배열의 참인 원소의 인덱스에 해당되는 행 배열 집합 추출
- 슬라이싱(열 추출) → 논리 연산 → 논리 인덱싱 → 2차원 배열(행 추출)
# 2차원 배열 논리 인덱싱
import numpy as np
arr = np.array([[1,2,3], [4,5,6]])
larr = arr[:, 0] % 2 == 0 # 슬라이싱(0열 추출) => 논리연산 => 1차원 논리배열 생성
print(arr[:, 0], larr)
print(arr[larr]) # 논리배열 논리 인덱싱 => 2차원 배열( 행 추출 ) 반환
실습) 2차원 배열에서 조건 만족 행 추출
# 2차원 배열에서 조건 만족 행 추출
lst = [[177, 77.1],
[183, 80.1],
[185, 78.3],
[173, 80.3]]
arr = np.array(lst)
print('몸무게가 80 이상')
print(arr[ arr[:, 1] >= 80.0]) # 슬라이싱(1열 추출) => 논리 연산 => 논리인덱싱
print('키가 180 이상')
print(arr[ arr[:, 0] >= 180.0]) # 슬라이싱 (0열 추출) => 논리 연산 => 논리인덱싱
넘파이 배열 생성 : zeros(), ones() , eye()
- zeros() 함수 → 모든 원소가 0인 배열 생성
- 인수 : 배열의 형태(shape)를 튜플 형식으로 전달
- ex) np.zeros((3, 4)) → 3행 4열 2차원 배열 반환, 모든원소 0
- ones() 함수 → 모든 원소가 1인 배열 생성
- 인수 : 배열의 형태(shape)를 튜플 형식으로 전달
- ex) np.ones((3, 4)) → 3행 4열 2차원 배열 반환, 모든원소 1
- eye() 함수 → 단위행렬 생성
- 인수 : 단위행렬의 크기(대각 원소의 개수)
- ex) np.eye(e) → 3행3열 단위행렬 반환(대각원소 1, 나머지 0)
- 해당 함수들은 실수 타입으로 생성해준다.
# 넘파이 배열 생성/초기화 함수
print(np.zeros((3, 4))) # 3행 4열 배열 생성, 모든 원소 0으로 초기화
print(np.ones((3, 4))) # 3행 4열 배열 생성, 모든 원소 1으로 초기화
print(np.eye(3)) # 3행 3열 단위행렬 생성, 대각원소 1, 나머지 0으로 초기화
넘파이 배열 생성 함수 : arange()
- 연속적 정수로 초기화된 배열 생성
- 형식 → np.arange([start,] stop, [step])
- start : 데이터 생성 시작 값, 생략시 0으로 처리
- stop : 데이터 생성 종료 값, stop-1까지 생성
- step : 데이터 생성 간격, 생략시 1로 처리
- == np.array(range([start,] stop, [step]))
# 넘파이 배열 생성 함수 : arange()
# arange() = np.array + range()
# 크기 10인 배열 생성, 0~9로 초기화
print(np.arange(10), np.array(range(10)))
# 크기 9인 배열 생성, 1~9로 초기화
print(np.arange(1, 10), np.array(range(1, 10)))
# 크기 5인 배열 생성, 0~8 짝수로 초기화
print(np.arange(0, 10, 2), np.array(range(0, 10, 2)))
넘파이 배열 생성 함수 : linspace(), logspace()
- linspace() 함수
- 형식 : np.linspace(start, stop, num=50)
- 크기가 num인 실수 배열
- start ~ stop까지 균등한 간격의 num개 실수로 초기화
- 형식 : np.linspace(start, stop, num=50)
- logspace() 함수
- 형식 : np.logspace(start, stop, num=50)
- 크기가 num인 실수 배열
- 10start ~ 10stop까지 로그스케일로 균등한 간격의 num개 실수로 초기화
- 형식 : np.logspace(start, stop, num=50)
넘파이 배열의 형태 변경 메소드
- reshape() 메소드
- 형식 → arr.reshape(shape)
- shape : 변경하고자 하는 형태를 튜플 형식으로 전달
- 1차원 배열 : (n, ), 2차원 배열 : (n, m), 3차원 배열 : (n, m, l)
- shape의 인덱스 값이 -1이면 변경 크기 자동 배정
- shape : 변경하고자 하는 형태를 튜플 형식으로 전달
- shape 형식의 새로운 배열 반환
- 변경 전, 변경 후 배열의 크기(size 속성)가 동일해야 함
- ex) arr.reshape(4, 2) → arr 배열을 6행 2열 배열로 형태 변경
- ex) arr.reshape(4, -1) → 4행, 열의 크기는 자동 배정
- 형식 → arr.reshape(shape)
- flatten() 메소드
- 형식 → arr.flatten() == arr.reshape(-1)
- 2차원 이상의 배열을 1차원 배열로 변경한 배열을 반환
- 2차원 배열 → 1차원 배열로 변환할 때 사용
# 넘파이 배열 형태 변경
import numpy as np
arr1 = np.arange(8) # 크기가 8인 1차원 배열 생성, 0~7로 초기화
print(arr1, '\n')
arr2 = arr1.reshape(2, 4) # 크기 8, 1차원 배열 => 2행 4열 2차원 배열로 변경
print(arr2, '\n')
print(arr2.flatten(), arr2.reshape(-1)) # 2행 4열 배열 => 1차원 배열로 변경
- 만약 위의 상태에서 reshape에서 오류가 발생하는 상황은 arr1이 7일 때는 2행 4열로 나누지 못해서 오류가 발생, reshape는 배열을 생성할 수 없을 때 오류가 발생할 수 있다.
난수 배열 생성
- np.random 모듈의 함수
- seed(n) 함수
- 난수 생성을 위한 초기값을 n으로 설정
- 초기값이 같으면, 같은 순서로 난수 생성됨
- seed(n) 함수
- rand(shape) 함수
- shape 형식의 난수 배열(ndarray 타입) 반환
- [0, 1) 사이 균일 분포의 실수형 난수 값으로 배열 원소 초기화
- randint(s, e, size=(shape)) 함수
- shape 형태의 난수 배열 (ndarray 타입) 반환
- [s, e-1] 사이 균일 분포의 정수형 난수 값으로 배열 원소 초기화
# 난수 배열 생성
import numpy as np
np.random.seed(2) # 난수 생성 초기값 설정, 값 변경시 Value들 달라짐
arr1 = np.random.rand(10) # 크기가 10인 1차원 난수배열 생성, (0, 1) 사이 난수
print(10*arr1 + 10) # 브로드캐스팅 연산으로 (10, 20) 사이 난수 생성
arr2 = np.random.randint(1, 11, size=(3, 5)) # 3행 5열 난수 배열 [1, 10] 사이 난수
print(arr2)
print(np.random.randint(1, 6, size=10)) # 크기 10, 1차원 난수 배열, [1, 5 ] 사이 난수
- Seed가 지정되어 있어 재실행을 해도 값이 변하지 않는다, Random 값을 변경하고 싶으면 Seed를 변경한다.
정규분포 난수 배열 생성
- rand(), randint() 함수 → 균일한 확률 분포의 난수 생성
- 정규 분포
- 평균값에서 발생확률이 가장 높고, 평균값에서 멀수록 발생확률 낮음
- 표준편차(σ)가 크면 클수록 데이터의 흩어짐이 커짐
- 정규 분포 난수 발생 함수
- np.random.normal(m, s, shape) 함수
- shape 형태 난수배열 반환, 정규분포(평균 m, 표준편차 s) 난수
- np.random.randn(d0, d1, ..., dn) 함수
- (d0, d1, ..., dn) 난수배열 반환, 정규분포(평균 0, 표준편차 1) 난수
- np.random.normal(m, s, shape) 함수
- ex) np.random.normal(0, 1, (2,5)) == np.random.randn(2, 5)
난수 관련 함수
- np.random.shuffle(arr)
- 넘파이 배열 arr의 순서를 랜덤하게 변경
- np.random.permutation(arr)
- 넘파이 배열 arr의 순서를 랜덤하게 변경한 배열 반환(배열 arr 불변)
- np.random.choice(arr, n)
- 넘파이 배열 arr에서 n개의 원소를 균등확률로 추출한 배열 반환
- np.random.choice(arr, n, replace=True, p)
- replace=True → 중복 추출 가능, replace=False → 중복 추출 제외
- p에는 표본들의 추출 확률값을 가지는 리스트 전달
- 넘파이 배열 arr에서 n개의 원소를 표본추출 확률로 추출한 배열 반환
import numpy as np
x = np.arange(1, 11)
np.random.shuffle(x) # 원본 배열의 순서 랜덤 변경
print(x)
y = np.arange(1, 11)
print(np.random.permutation(y)) # 순서 랜덤 변경 배열 반환, 원본 배열 변경 없음
print(y)
fruits = ['apple', 'banana', 'cherries', 'durian', 'grapes', 'lemon', 'mango']
pb = [0.1, 0, 0.2, 0.5, 0.1, 0.05, 0.05] # 표본 추출 확률 리스트
print(np.random.choice(fruits, 3, replace=False, p=pb)) # 랜덤 추출, 중복없이
넘파이 배열의 속성 : T
- 전치 행렬 변환
- arr.T
- == arr.transpose()
- 배열 arr의 전치 행렬 값
- 배열 arr를 90도 회전 배열
- (m, n) 배열 → (n, m) 배열
- arr.T
arr = np.array([[1, 2], [3, 4], [5, 6]])
print(arr) # 3행 2열 배열
print()
print(arr.T) # 2행 3열 배열로 변경
넘파이 배열 평균 계산
- mean() 함수
- 호출 → np.mean(arr, axis=0)
- 1차원 배열의 평균 계산시 axis 생략
- 호출 → np.mean(arr, axis=0)
- mean() 메소드
- 호출 → arr.mean(axis=0)
- np.mean(arr, axis=0) == arr.mean(axis=0)
- 2차원 배열 axis=0 → 행방향 평균 → 각 열의 평균값 배열 반환
- 2차원 배열 axis=1 → 열방향 평균 → 각 행의 평균값 배열 반환
# 넘파이 배열 평균 계산
import numpy as np
arr = np.array([[99, 93, 60], [98, 82, 93], [93, 65, 81], [78, 82, 81]])
print(arr, '\n')
print(np.mean(arr, axis=0)) # 행방향 평균 => 각 열의 평균 => 열크기 1차원 배열 함수 사용
print(arr.mean(axis=0), '\n') # 메소드 사용
print(np.mean(arr, axis=1)) # 열방향 평균 => 각 행의 평균 => 행크기 1차원 배열 함수 사용
print(arr.mean(axis=1)) # 메소드 사용
넘파이 unique() 함수
- np.unique(arr) 함수
- 넘파이 배열의 고유 값 출력 → 1차원 배열 반환
- np.unique(arr, axis) 함수
- 넘파이 배열 arr가 2차원 배열일 때
- axis=0 → 넘파이 배열의 고유 행 출력 → 2차원 배열 반환
- axis=1 → 넘파이 배열의 고유 열 출력 → 2차원 배열 반환
- 넘파이 배열 arr가 2차원 배열일 때
a = np.array([[2, 3, 2],
[2, 3, 2],
[3, 2, 3]])
print(np.unique(a)) # 고유 값 출력 => 1차원 배열 - 중복 제거한 값 요소만 출력
print(np.unique(a, axis=0)) # 고유 행 출력 => 2차원 배열 - 중복 제거한 행만 출력
print(np.unique(a, axis=1)) # 고유 열 출력 => 2차원 배열 - 중복 제거한 열만 출력
넘파이 배열 합치기
- np.concatenate((arr1, arr2), axis) 함수
- 두 배열이 1차원 배열일 때
- axis=0 → 열 방향으로 연결
- 두 배열이 2차원 배열일 때
- axis=0 → 행 방향으로 연결
- axis=1 → 열 방향으로 연결
- 두 배열이 1차원 배열일 때
# 넘파이 배열 합치기
arr1 = np.arange(8).reshape(2,4) # 2*4 2차원 배열
arr2 = np.arange(8, 16).reshape(2,4) # 2*4 2차원 배열
print(arr1)
print(arr2)
print(np.concatenate((arr1, arr2), axis=0)) # 2차원 배열 행 방향 연결
print(np.concatenate((arr1, arr2), axis=1)) # 2차원 배열 열 방향 연결
넘파이 배열 분리
- np.split(arr, n, axis) 함수
- 두 배열이 1차원 배열일 때
- axis=0 → 열 방향 n개의 배열로 분리 = np.hsplit(arr, n)
- 두 배열이 2차원 배열일 때
- axis=0 → 행 방향 n개의 배열로 분리 = np.vsplit(arr, n)
- axis=1 → 열 방향 n개의 배열로 분리 = np.hsplit(arr, n)
- 두 배열이 1차원 배열일 때
# 넘파이 배열 분리
arr = np.arange(8).reshape(2,4)
print(arr, '\n') # arr.shape == (2,4), 2*4 행렬
up, down = np.split(arr, 2, axis=0) # 2차원 배열 행방향 분리
print(up)
print(down, '\n')
left, right = np.split(arr, 2, axis=1) # 2차원 배열 행방향 분리
print(left)
print(right)
기타 넘파이 함수
- np.all(arr) 함수 == all(arr) 함수
- 넘파이 배열 arr의 모든 데이터가 참이면 True, 아니면 False 반환
- np.any(arr) 함수 == any(arr) 함수
- 넘파이 배열 arr의 모든 데이터가 거짓이면 False, 아니면 True 반환
- np.isnan(arr) 함수
- 넘파이 배열 arr의 각 원소에 대해 NaN값이면 True, 아니면 False를 가지는 배열 반환 → 논리 배열 반환 → 논리 인덱싱에 활용
- np.isfinite(arr) 함수
- 넘파이 배열 arr의 각 원소에 대해 셀 수 있는 숫자이면 True, 아니면 False를 가지는 배열 반환 → 논리 배열 반환
- 셀 수 없는 숫자 : np.NaN, np.inf
# 기타 넘파이 함수
arr1 = np.array([1, 0, 1, 0])
print(np.all(arr1)) # 모든 원소가 참이면 True 반환
print(np.any(arr1)) # 원소 중에 참이 있으면 True 반환
arr2 = np.array([1, np.NaN, 1, np.inf])
print(np.isnan(arr2)) # 각 원소가 숫자인지 체크 => 논리 배열로 반환된다
print(np.isfinite(arr2)) # 각 원소가 셀 수 있는 숫자인지 체크 => 논리 배열로 반환된다.
넘파이(numpy) 배열
- 리스트처럼 여러 개의 값들을 저장할 수 있는 자료구조
- 리스트는 다양한 자료형의 데이터 저장 가능
- 넘파이 배열은 같은 자료형의 데이터 저장
- 리스트보다 데이터 처리속도가 빠름
- 리스트는 데이터 접근을 위해 이중 참조 ⇒ 해당 이유 때문에 리스트의 처리속도가 느림
- 리스트는 객체 배열
- 넘파이 배열은 한번의 참조로 데이터 접근 가능
- 리스트는 데이터 접근을 위해 이중 참조 ⇒ 해당 이유 때문에 리스트의 처리속도가 느림
- 대량의 데이터를 빠르게 처리하려면 넘파이 배열 필요
- 데이터 과학, 인공지능 분야에서 넘파이 배열 사용
- 넘파이 배열은 ndarray 클래스로 구현
- ndarray 클래스 장점
- C언어에 기반한 배열 구조이므로 메모리를 적게 차지하고 속도가 빠르다.
- 배열과 배열 간에 수학적인 연산을 적용
- 배열의 모든 원소 적용되는 연산자 함수 제공
- 행렬 연산
- 고급 연산자와 풍부한 함수 제공
- 브로드 캐스팅
- 인덱싱
- 슬라이싱
- 논리적 인덱싱
- 난수 배열
- 다차원 배열 표현 가능
- 1차원 배열 → 인덱스 1개 → arr[j] (열)
- 2차원 배열 → 인덱스 2개 ⇒ arr[i][j] == arr[i, j] (행, 열)
- 3차원 배열 → 인덱스 3개 → arr[k][i][j] == arr[k, i, j] (면, 행, 열)
- 배열의 차원을 축(axis) 이라 함
넘파이 배열 생성
- 넘파이를 사용하기위해 넘파이 패키지 불러옴
- ex) import numpy
- 넘파일 모듈이름을 간략히 표현하기 위해 별칭 부여
- ex) import numpy as np
- 넘파이 배열 생성자
- array( ) 함수
- 초기값 전달을 위해 생성자에 리스트(배열, range객체) 전달
- ex) arr = np.array([1,2,3]) → arr는 배열이름 ( 참조변수 )
- array( ) 함수
넘파이 배열의 속성(필드)
- ndarray 클래스의 속성(필드)
- ndim → 배열의 차원
- shape → 배열의 형태 : 튜플로 표현
- ex) (3, ) → 3열의 1차원 배열
- ex) (2, 3) → 2행, 3열의 2차원 배열
- ex) (4, 2, 3) → 4면, 2행, 3열의 3차원 배열
- dtype → 원소의 타입
- itemsize → 원소의 할당크기
- ex) int32 → 4바이트
- size → 배열 전체 크기(원소의 총 개수)
# 넘파이 배열의 속성(필드)
import numpy as np
arr1 = np.array([1, 2, 3])
print(arr1)
print(arr1.ndim, arr1.shape, arr1.dtype, arr1.itemsize, arr1.size, '\n')
arr2 = np.array([[1,2,3], [4, 5, 6]])
print(arr2)
print(arr2.ndim, arr2.shape, arr2.dtype, arr2.itemsize, arr2.size, '\n')
arr3 = np.array([[[1,1,1], [2,2,2]], [[3,3,3], [4,4,4]]])
print(arr3)
print(arr3.ndim, arr3.shape, arr3.dtype, arr3.itemsize, arr3.size, '\n')
넘파이 배열의 연산 : 브로드 캐스팅
- ndarray 클래스의 연산자 함수
- 형식 → 넘파이배열 산술연산자(op) 값(v)
- 넘파이 배열의 모든 원소에 값과 산술연산 적용한 배열 반환
- ex) arr1 + 3 → 배열의 모든 원소에 +3을 적용한 배열 반환
- ex) arr1 ** 2 → 배열의 모든 원소에 **2를 적용한 배열 반환
- 형식 → 넘파이배열 산술연산자(op) 값(v)
리스트와 넘파이 배열 + 연산의 차이
- 넘파이 배열 + 넘파이 배열 : 벡터화 연산(원소별 덧셈)
- 넘파이 배열의 +연산자는 배열 원소별 덧셈 연산자
- 리스트 + 리스트 = 두개의 리스트가 연결됨
# 리스트와 넘파이 배열 + 연산의 차이
import numpy as np
lst1 = [1, 2, 3]
lst2 = [4, 5, 6]
print(lst1 + lst2) # 리스트 + 연산자 ==> 리스트 연결 연산자
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
print(arr1 + arr2) # 넘파이배열 + 연산자 ==> 원소별 덧셈 연산자
#시험에 나올수 있음.
# 넘파이 배열은 print 시 쉼표가 없음!!!!!!!
넘파이 배열 곱셈 연산자 : *와 @
- 넘파이 배열 * 넘파이 배열 → 벡터화 연산(원소별 곱셈)
- 넘파이 배열 @ 넘파이 배열 → 행렬 곱셈
- (p, q) 배열 @ (q, r) 배열 → (p, r) 배열 반환
실습 . BMI 계산
- n명 키와 몸무메가 주어졌을 때, 넘파이 배열을 이용하여 n명의 BMI를 일괄 처리
# 실습. bmi 계산
import numpy as np
h = [1.83, 1.75, 1.71, 1.85, 1.77, 1.73]
w = [80, 74, 59, 90, 77, 78]
harr = np.array(h)
warr = np.array(w)
bmi = warr/harr**2
- 넘파이 배열을 사용함으로써 for문을 안써서 코드 작성시간이 획기적으로 줄여질수 있다
넘파이 배열 인덱싱과 슬라이싱
- 넘파이 배열도 리스트처럼 인덱싱과 슬라이싱 지원
- 인덱싱 → 특정 요소를 추출(정수 인덱싱)
- arr[i] → i번째 원소 반환
- 첫번째 원소의 인덱스 = 0
- arr[i] → i번째 원소 반환
- 음수 인덱스 –i → 뒤에서 i번째 원소 반환
- arr[-1] == arr[n-1] ← n의 배열의 크기
- cf) 넘파이 배열의 인덱싱 : 정수 인덱싱, 배열 인덱싱, 논리 인덱싱
- 인덱싱 → 특정 요소를 추출(정수 인덱싱)
- 슬라이싱 → 특정 요소 집합을 추출
- arr[ s : e ] → arr[s]에서 arr[e-1] 사이의 원소 집합의 배열 반환
- 시작 인덱스와 종료 인덱스 생략 가능
- arr[ : e ] → arr[0]에서 arr[e-1] 사이의 원소 집합의 배열 반환
- arr[ s : ] → arr[s]에서 arr[n-1] 사이의 원소 집합의 배열 반환
- arr[ : ] → 배열의 모든 원소 집합의 배열 반환
- arr[ : ] == arr[0: ] == arr[ :n] == arr[0:n] ← n은 배열의 크기
- arr[ s : e ] → arr[s]에서 arr[e-1] 사이의 원소 집합의 배열 반환
넘파이는 모든 배열의 타입이 같아야한다.
리스트는 다양한 타입이 저장이 가능한데 그 이유는 참조주소만 참조하기때문에 가능하다. 그래서 속도도 느리다.
2차원 배열 인덱싱
- 2차원 배열의 2가지 인덱싱 방법
- arr[i][j] == arr[i,j]
- i행, j열의 원소 반환
- arr[i] → i행 원소 집합(1차원 배열) 반환
- arr[i][j] == arr[i,j]
import numpy as np
arr = np.array([[1,2,3], [4,5,6]])
print(arr[0]) # 0행의 원소 집합(1차원 배열) 반환
print(arr[0][1], arr[0,1]) # 0행, 1열의 원소 반환
print(arr[-1][-1], arr[-1, -1]) # 마지막 행, 열의 원소 반환
arr[0,0] = 7.7 # 배열arr는 정수배열로 생성되었다 -> 실수 입력시 정수로 타입 변환된다.
print(arr)
2차원 배열 슬라이싱
- 2차원 배열 슬라이싱 방법
- arr[sr:er][sc:ec] == arr[sr:er, sc:ec]
- sr행~(er-1)행, sc열~(ec-1) 열 사이의 원소 집합을 배열로 반환
- 슬라이싱 범위를 나타내는 인덱스 생략 가능
- 시작 인덱스 생략 → 0, 끝 인덱스 생략 → n(행/열의 크기)
- 2차원 배열 슬라이싱 반환 값의 차원
- arr[범위, 인덱스], arr[인덱스, 범위] → 1차원 배열 반환
- arr[범위, 범위] → 2차원 배열 반환
- 슬라이싱 범위 형식
- 시작인덱스 : 끝 인덱스 : 인덱스간격
- ex) arr[0, 0:n:2] → 0행, 짝수 인덱스열(0, 2, 4, …) 1차원 배열 반환
- 시작인덱스 : 끝 인덱스 : 인덱스간격
# 2차원 배열 슬라이싱
import numpy as np
arr = np.array([[1,2,3], [4,5,6]])
print(arr[0, :]) # 1차원 배열
print(arr[0:1, :]) # 2차원 배열 만약 0:2 하면 다음 열의 값도 나옴
# [0: ,:] 하면 모든 행, 열 출력
print(arr[0, ::2]) # 짝수인덱스열 1차원 배열
논리 인덱싱(Logical indexing)
- 논리데이터 배열(논리 배열)을 인덱스로 사용
- 배열과 인덱스로 사용할 논리배열은 같은 크기(shape 동일)
- 논리배열의 원소가 참(True)인 인덱스에 해당되는 배열의 원소들만 추출
- 반환 배열의 크기 = 논리배열의 참인 원소의 수
- cf) 배열 인덱싱 → 인덱스배열로 인덱싱 : 해당 인덱스 원소만 추출
- 논리배열 생성
- 넘파이 배열에 논리 연산 적용(브로드캐스팅)
- • ex) arr > 0 → 양인 원소는 True, 다른 원소는 False인 논리배열 반환
- 장점 : 반복문을 쓰지 않고 필터링을 할 수 있다.
- 넘파이 배열에 논리 연산 적용(브로드캐스팅)
# 논리 인덱싱
arr = np.array([1,2,3,4,5])
print(arr[ [0, 2, 4] ]) # 배열 인덱싱 => 짝수 인덱스에 위치한 원소만 추출 : 1차원 배열 반환
larr = arr >= 3 # 논리 배열 생성 : 배열에 논리 연산 적용
print(larr)
print(arr[larr]) # 논리 인덱싱 => 1차원 배열 반환
2차원 배열 논리 인덱싱
- 논리배열이 2차원 배열일 때
- 2차원 배열과 같은 shape의 논리배열 필요
- 2차원 배열에 논리 연산 적용(브로드캐스팅)
- arr[2차원_논리배열] → 1차원 배열 반환
- 논리배열의 참인 원소의 인덱스에 위치한 배열의 원소들만 추출
- 2차원 배열과 같은 shape의 논리배열 필요
# 2차원 배열 논리 인덱싱
import numpy as np
arr = np.array([[1,2,3], [4,5,6]])
larr = arr % 2 == 0 # 짝수인 원소만 True 2차원 논리배열 생성
print(larr)
print(arr[larr]) # 논리 인덱싱 => 1차원 배열 반환
- 논리배열이 1차원 배열일 때
- 2차원 배열의 행의 크기와 같은 1차원 논리배열 필요
- 2차원 배열 슬라이싱(열 추출) 후 논리연산 → 1차원 논리배열 생성
- ex) arr[:, 0] % 2 == 0 → 0열 배열(1차원 배열)에 논리 연산 적용
- arr[1차원_논리배열] → 2차원 배열 반환
- 논리배열의 참인 원소의 인덱스에 해당되는 행 배열 집합 추출
- 슬라이싱(열 추출) → 논리 연산 → 논리 인덱싱 → 2차원 배열(행 추출)
# 2차원 배열 논리 인덱싱
import numpy as np
arr = np.array([[1,2,3], [4,5,6]])
larr = arr[:, 0] % 2 == 0 # 슬라이싱(0열 추출) => 논리연산 => 1차원 논리배열 생성
print(arr[:, 0], larr)
print(arr[larr]) # 논리배열 논리 인덱싱 => 2차원 배열( 행 추출 ) 반환
실습) 2차원 배열에서 조건 만족 행 추출
# 2차원 배열에서 조건 만족 행 추출
lst = [[177, 77.1],
[183, 80.1],
[185, 78.3],
[173, 80.3]]
arr = np.array(lst)
print('몸무게가 80 이상')
print(arr[ arr[:, 1] >= 80.0]) # 슬라이싱(1열 추출) => 논리 연산 => 논리인덱싱
print('키가 180 이상')
print(arr[ arr[:, 0] >= 180.0]) # 슬라이싱 (0열 추출) => 논리 연산 => 논리인덱싱
넘파이 배열 생성 : zeros(), ones() , eye()
- zeros() 함수 → 모든 원소가 0인 배열 생성
- 인수 : 배열의 형태(shape)를 튜플 형식으로 전달
- ex) np.zeros((3, 4)) → 3행 4열 2차원 배열 반환, 모든원소 0
- ones() 함수 → 모든 원소가 1인 배열 생성
- 인수 : 배열의 형태(shape)를 튜플 형식으로 전달
- ex) np.ones((3, 4)) → 3행 4열 2차원 배열 반환, 모든원소 1
- eye() 함수 → 단위행렬 생성
- 인수 : 단위행렬의 크기(대각 원소의 개수)
- ex) np.eye(e) → 3행3열 단위행렬 반환(대각원소 1, 나머지 0)
- 해당 함수들은 실수 타입으로 생성해준다.
# 넘파이 배열 생성/초기화 함수
print(np.zeros((3, 4))) # 3행 4열 배열 생성, 모든 원소 0으로 초기화
print(np.ones((3, 4))) # 3행 4열 배열 생성, 모든 원소 1으로 초기화
print(np.eye(3)) # 3행 3열 단위행렬 생성, 대각원소 1, 나머지 0으로 초기화
넘파이 배열 생성 함수 : arange()
- 연속적 정수로 초기화된 배열 생성
- 형식 → np.arange([start,] stop, [step])
- start : 데이터 생성 시작 값, 생략시 0으로 처리
- stop : 데이터 생성 종료 값, stop-1까지 생성
- step : 데이터 생성 간격, 생략시 1로 처리
- == np.array(range([start,] stop, [step]))
# 넘파이 배열 생성 함수 : arange()
# arange() = np.array + range()
# 크기 10인 배열 생성, 0~9로 초기화
print(np.arange(10), np.array(range(10)))
# 크기 9인 배열 생성, 1~9로 초기화
print(np.arange(1, 10), np.array(range(1, 10)))
# 크기 5인 배열 생성, 0~8 짝수로 초기화
print(np.arange(0, 10, 2), np.array(range(0, 10, 2)))
넘파이 배열 생성 함수 : linspace(), logspace()
- linspace() 함수
- 형식 : np.linspace(start, stop, num=50)
- 크기가 num인 실수 배열
- start ~ stop까지 균등한 간격의 num개 실수로 초기화
- 형식 : np.linspace(start, stop, num=50)
- logspace() 함수
- 형식 : np.logspace(start, stop, num=50)
- 크기가 num인 실수 배열
- 10start ~ 10stop까지 로그스케일로 균등한 간격의 num개 실수로 초기화
- 형식 : np.logspace(start, stop, num=50)
넘파이 배열의 형태 변경 메소드
- reshape() 메소드
- 형식 → arr.reshape(shape)
- shape : 변경하고자 하는 형태를 튜플 형식으로 전달
- 1차원 배열 : (n, ), 2차원 배열 : (n, m), 3차원 배열 : (n, m, l)
- shape의 인덱스 값이 -1이면 변경 크기 자동 배정
- shape : 변경하고자 하는 형태를 튜플 형식으로 전달
- shape 형식의 새로운 배열 반환
- 변경 전, 변경 후 배열의 크기(size 속성)가 동일해야 함
- ex) arr.reshape(4, 2) → arr 배열을 6행 2열 배열로 형태 변경
- ex) arr.reshape(4, -1) → 4행, 열의 크기는 자동 배정
- 형식 → arr.reshape(shape)
- flatten() 메소드
- 형식 → arr.flatten() == arr.reshape(-1)
- 2차원 이상의 배열을 1차원 배열로 변경한 배열을 반환
- 2차원 배열 → 1차원 배열로 변환할 때 사용
# 넘파이 배열 형태 변경
import numpy as np
arr1 = np.arange(8) # 크기가 8인 1차원 배열 생성, 0~7로 초기화
print(arr1, '\n')
arr2 = arr1.reshape(2, 4) # 크기 8, 1차원 배열 => 2행 4열 2차원 배열로 변경
print(arr2, '\n')
print(arr2.flatten(), arr2.reshape(-1)) # 2행 4열 배열 => 1차원 배열로 변경
- 만약 위의 상태에서 reshape에서 오류가 발생하는 상황은 arr1이 7일 때는 2행 4열로 나누지 못해서 오류가 발생, reshape는 배열을 생성할 수 없을 때 오류가 발생할 수 있다.
난수 배열 생성
- np.random 모듈의 함수
- seed(n) 함수
- 난수 생성을 위한 초기값을 n으로 설정
- 초기값이 같으면, 같은 순서로 난수 생성됨
- seed(n) 함수
- rand(shape) 함수
- shape 형식의 난수 배열(ndarray 타입) 반환
- [0, 1) 사이 균일 분포의 실수형 난수 값으로 배열 원소 초기화
- randint(s, e, size=(shape)) 함수
- shape 형태의 난수 배열 (ndarray 타입) 반환
- [s, e-1] 사이 균일 분포의 정수형 난수 값으로 배열 원소 초기화
# 난수 배열 생성
import numpy as np
np.random.seed(2) # 난수 생성 초기값 설정, 값 변경시 Value들 달라짐
arr1 = np.random.rand(10) # 크기가 10인 1차원 난수배열 생성, (0, 1) 사이 난수
print(10*arr1 + 10) # 브로드캐스팅 연산으로 (10, 20) 사이 난수 생성
arr2 = np.random.randint(1, 11, size=(3, 5)) # 3행 5열 난수 배열 [1, 10] 사이 난수
print(arr2)
print(np.random.randint(1, 6, size=10)) # 크기 10, 1차원 난수 배열, [1, 5 ] 사이 난수
- Seed가 지정되어 있어 재실행을 해도 값이 변하지 않는다, Random 값을 변경하고 싶으면 Seed를 변경한다.
정규분포 난수 배열 생성
- rand(), randint() 함수 → 균일한 확률 분포의 난수 생성
- 정규 분포
- 평균값에서 발생확률이 가장 높고, 평균값에서 멀수록 발생확률 낮음
- 표준편차(σ)가 크면 클수록 데이터의 흩어짐이 커짐
- 정규 분포 난수 발생 함수
- np.random.normal(m, s, shape) 함수
- shape 형태 난수배열 반환, 정규분포(평균 m, 표준편차 s) 난수
- np.random.randn(d0, d1, ..., dn) 함수
- (d0, d1, ..., dn) 난수배열 반환, 정규분포(평균 0, 표준편차 1) 난수
- np.random.normal(m, s, shape) 함수
- ex) np.random.normal(0, 1, (2,5)) == np.random.randn(2, 5)
난수 관련 함수
- np.random.shuffle(arr)
- 넘파이 배열 arr의 순서를 랜덤하게 변경
- np.random.permutation(arr)
- 넘파이 배열 arr의 순서를 랜덤하게 변경한 배열 반환(배열 arr 불변)
- np.random.choice(arr, n)
- 넘파이 배열 arr에서 n개의 원소를 균등확률로 추출한 배열 반환
- np.random.choice(arr, n, replace=True, p)
- replace=True → 중복 추출 가능, replace=False → 중복 추출 제외
- p에는 표본들의 추출 확률값을 가지는 리스트 전달
- 넘파이 배열 arr에서 n개의 원소를 표본추출 확률로 추출한 배열 반환
import numpy as np
x = np.arange(1, 11)
np.random.shuffle(x) # 원본 배열의 순서 랜덤 변경
print(x)
y = np.arange(1, 11)
print(np.random.permutation(y)) # 순서 랜덤 변경 배열 반환, 원본 배열 변경 없음
print(y)
fruits = ['apple', 'banana', 'cherries', 'durian', 'grapes', 'lemon', 'mango']
pb = [0.1, 0, 0.2, 0.5, 0.1, 0.05, 0.05] # 표본 추출 확률 리스트
print(np.random.choice(fruits, 3, replace=False, p=pb)) # 랜덤 추출, 중복없이
넘파이 배열의 속성 : T
- 전치 행렬 변환
- arr.T
- == arr.transpose()
- 배열 arr의 전치 행렬 값
- 배열 arr를 90도 회전 배열
- (m, n) 배열 → (n, m) 배열
- arr.T
arr = np.array([[1, 2], [3, 4], [5, 6]])
print(arr) # 3행 2열 배열
print()
print(arr.T) # 2행 3열 배열로 변경
넘파이 배열 평균 계산
- mean() 함수
- 호출 → np.mean(arr, axis=0)
- 1차원 배열의 평균 계산시 axis 생략
- 호출 → np.mean(arr, axis=0)
- mean() 메소드
- 호출 → arr.mean(axis=0)
- np.mean(arr, axis=0) == arr.mean(axis=0)
- 2차원 배열 axis=0 → 행방향 평균 → 각 열의 평균값 배열 반환
- 2차원 배열 axis=1 → 열방향 평균 → 각 행의 평균값 배열 반환
# 넘파이 배열 평균 계산
import numpy as np
arr = np.array([[99, 93, 60], [98, 82, 93], [93, 65, 81], [78, 82, 81]])
print(arr, '\n')
print(np.mean(arr, axis=0)) # 행방향 평균 => 각 열의 평균 => 열크기 1차원 배열 함수 사용
print(arr.mean(axis=0), '\n') # 메소드 사용
print(np.mean(arr, axis=1)) # 열방향 평균 => 각 행의 평균 => 행크기 1차원 배열 함수 사용
print(arr.mean(axis=1)) # 메소드 사용
넘파이 unique() 함수
- np.unique(arr) 함수
- 넘파이 배열의 고유 값 출력 → 1차원 배열 반환
- np.unique(arr, axis) 함수
- 넘파이 배열 arr가 2차원 배열일 때
- axis=0 → 넘파이 배열의 고유 행 출력 → 2차원 배열 반환
- axis=1 → 넘파이 배열의 고유 열 출력 → 2차원 배열 반환
- 넘파이 배열 arr가 2차원 배열일 때
a = np.array([[2, 3, 2],
[2, 3, 2],
[3, 2, 3]])
print(np.unique(a)) # 고유 값 출력 => 1차원 배열 - 중복 제거한 값 요소만 출력
print(np.unique(a, axis=0)) # 고유 행 출력 => 2차원 배열 - 중복 제거한 행만 출력
print(np.unique(a, axis=1)) # 고유 열 출력 => 2차원 배열 - 중복 제거한 열만 출력
넘파이 배열 합치기
- np.concatenate((arr1, arr2), axis) 함수
- 두 배열이 1차원 배열일 때
- axis=0 → 열 방향으로 연결
- 두 배열이 2차원 배열일 때
- axis=0 → 행 방향으로 연결
- axis=1 → 열 방향으로 연결
- 두 배열이 1차원 배열일 때
# 넘파이 배열 합치기
arr1 = np.arange(8).reshape(2,4) # 2*4 2차원 배열
arr2 = np.arange(8, 16).reshape(2,4) # 2*4 2차원 배열
print(arr1)
print(arr2)
print(np.concatenate((arr1, arr2), axis=0)) # 2차원 배열 행 방향 연결
print(np.concatenate((arr1, arr2), axis=1)) # 2차원 배열 열 방향 연결
넘파이 배열 분리
- np.split(arr, n, axis) 함수
- 두 배열이 1차원 배열일 때
- axis=0 → 열 방향 n개의 배열로 분리 = np.hsplit(arr, n)
- 두 배열이 2차원 배열일 때
- axis=0 → 행 방향 n개의 배열로 분리 = np.vsplit(arr, n)
- axis=1 → 열 방향 n개의 배열로 분리 = np.hsplit(arr, n)
- 두 배열이 1차원 배열일 때
# 넘파이 배열 분리
arr = np.arange(8).reshape(2,4)
print(arr, '\n') # arr.shape == (2,4), 2*4 행렬
up, down = np.split(arr, 2, axis=0) # 2차원 배열 행방향 분리
print(up)
print(down, '\n')
left, right = np.split(arr, 2, axis=1) # 2차원 배열 행방향 분리
print(left)
print(right)
기타 넘파이 함수
- np.all(arr) 함수 == all(arr) 함수
- 넘파이 배열 arr의 모든 데이터가 참이면 True, 아니면 False 반환
- np.any(arr) 함수 == any(arr) 함수
- 넘파이 배열 arr의 모든 데이터가 거짓이면 False, 아니면 True 반환
- np.isnan(arr) 함수
- 넘파이 배열 arr의 각 원소에 대해 NaN값이면 True, 아니면 False를 가지는 배열 반환 → 논리 배열 반환 → 논리 인덱싱에 활용
- np.isfinite(arr) 함수
- 넘파이 배열 arr의 각 원소에 대해 셀 수 있는 숫자이면 True, 아니면 False를 가지는 배열 반환 → 논리 배열 반환
- 셀 수 없는 숫자 : np.NaN, np.inf
# 기타 넘파이 함수
arr1 = np.array([1, 0, 1, 0])
print(np.all(arr1)) # 모든 원소가 참이면 True 반환
print(np.any(arr1)) # 원소 중에 참이 있으면 True 반환
arr2 = np.array([1, np.NaN, 1, np.inf])
print(np.isnan(arr2)) # 각 원소가 숫자인지 체크 => 논리 배열로 반환된다
print(np.isfinite(arr2)) # 각 원소가 셀 수 있는 숫자인지 체크 => 논리 배열로 반환된다.