- numpy란? (Numeric Python)
고성능의 수치계산과 선형대수학을 위해 제작된 Python 라이브러리
벡터 및 행렬 연산에 매우 편리한 기능 제공
- np.array()
- Array 객체를 생성하는 메소드
- np.array([1,2,3,4], dtype=np.데이터타입)
- 내부 요소 차이
- list : 내부 요소는 다양한 데이터타입을 갖는다.
- array : 내부 요소는 하나의 데이터타입으로 일관된다.ss = ['tom', 'james', 'oscar', 1] print(ss, type(ss)) # 리스트 타입 # ['tom', 'james', 'oscar', 1] <class 'list'> ss2 = np.array(ss) # array 형으로 형변환 print(ss2, type(ss2)) # numpy의 ndarray 클래스 타입 # ['tom' 'james' 'oscar' '1'] <class 'numpy.ndarray'>
- Array 내부 요소 데이터타입의 자동 형변환 특징
- array 내부에는 하나의 데이터타입으로 통일되야 한다.
- 서로 다른 타입이 존재하면 하나의 타입으로 자동 형변환 발생
💡 array 데이터타입 우선순위 : [ int < float < str ]
- 메모리 사용 차이
- list : 내부의 개별 요소가 개별 인스턴스로 따로 저장됨
ex) 내부 요소 개수가 8개라면 각 요소는 8개의 다른 저장소 블록에 따로 저장됨- array : 내부의 개별 요소가 하나의 인스턴스로 저장됨
ex) 내부 요소 개수가 8개라면 전체가 하나의 저장소 블록에 저장됨li = list(range(1, 10)) print(li) # [1, 2, 3, 4, 5, 6, 7, 8, 9] print('[0, 1] 인덱스 주소 : ', id(li[0]), id(li[1])) # [0, 1] 인덱스 주소 : 2458407495984 2458407496016 # -> 두개의 인스턴스 주소가 서로 다르다. num_arr = np.array(li) print(num_arr) # [1 2 3 4 5 6 7 8 9] print('[0, 1] 인덱스 주소 : ', id(num_arr[0]), id(num_arr[1])) # [0, 1] 인덱스 주소 : 2458454022768 2458454022768 # -> 두개의 인스턴스 주소가 동일하다.
- list 특징 (개별 인스턴스로 저장)
- 장점 : 유연성이 높다.
- 단점 : 비효율적 메모리 사용
- array 특징 (하나의 인스턴스로 저장)
- 장점 : 메모리의 효율적 사용
- 단점 : 유연성이 낮다.
- 연산자 적용 결과
- list : 리스트에 연산자 적용 시, 리스트를 문자열로 처리함
- array : 내부 요소 각각에 연산자 적용 가능print(li * 2) # 문자열 곱하기 연산자로 인식 # [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(num_arr * 2) # 각 요소에 곱하기 연산이 적용 # [ 2 4 6 8 10 12 14 16 18]
- 내장 함수
- type(arr) : 해당 객체의 타입 반환num_arr = np.arange(1, 10) print(type(num_arr)) # 타입 : <class 'numpy.ndarray'>
- 필드
- arr.dtype : 내부 요소 타입 반환
- arr.shape : 몇차원의 어떤 형태를 갖고 있는지를 반환
- arr.ndim : 행의 개수 반환
- arr.size : 내부 요소의 전체 개수 반환num_arr = np.arange(1, 10) print(num_arr.dtype) # int32 print(num_arr.shape) # (9,) => 1차원의 9개 요소를 갖는 벡터 print(num_arr.ndim) # 1 => 행개수 print(num_arr.size) # 9 => 행개수 * 열개수
- (n x n) array
- np.zeros((행,열)) : 행 * 열을 0으로 채운 array
- np.ones((행,열)) : 행 * 열을 1로 채운 array
- np.full((행,열), fill_value=값) : 행 * 열을 값으로 채운 array
- np.eye((행,열)) : 행 * 열에서 주대각을 1로 채우고 나머지는 0으로 채움print( np.zeros((2,2)) ) # 전체 0으로 채우기 # [[0. 0.] # [0. 0.]] print( np.ones((2,2)) ) # 전체 1로 채우기 # [[1. 1.] # [1. 1.]] print( np.full((2,2), fill_value=7) ) # 전체 7로 채우기 # [[7 7] # [7 7]] print( np.eye(3) ) # 주대각 = 1, 나머지 = 0 # [[1. 0. 0.] # [0. 1. 0.] # [0. 0. 1.]]
- np.random을 이용한 균등분포와 정규분포의 차이
- np.random.seed(값) : 매번 동일한 값을 추출하기 위한 시드값 설정
- np.random.rand(추출개수) : 0 ~ 1 균일분포 표준정규분포 난수 추출
- np.random.randn(추출개수) : 표준편차1, 평균0의 가우시안 표준정규분포 난수 추출
- np.random.randint(시작, 끝) : 지정 범위 사이의 정수형 난수 1개 추출np.random.seed(0) print( np.random.rand(5) ) # 균등분포 (0 ~ 1) # [0.5488135 0.71518937 0.60276338 0.54488318 0.4236548 ] print( np.random.randn(5) ) # 가우시안 정규분포 # [-0.84272405 1.96992445 1.26611853 -0.50587654 2.54520078] print( np.random.randint(10) ) # 5 # 참고 사항 print(np.mean(np.random.rand(5000))) # 균등분포에 대해 확률변수 개수가 많아질수록 0.5에 수렴함 # 0.503702391541436 print(np.mean(np.random.randn(5000))) # 정규분포에 대해 확률변수 개수가 많아질수록 0에 수렴함 # 0.003258670460904787
- np.arange() 메소드
- list(range(1, 10) : 1~9 까지의 값을 갖는 list
- np.array(range(1, 10)) : 1~9 까지의 값을 갖는 array
- np.arange(1, 10) : 1~9 까지의 값을 갖는 arrayprint(list(range(1, 10))) # [1, 2, 3, 4, 5, 6, 7, 8, 9] print(np.array(range(1, 10))) # [1 2 3 4 5 6 7 8 9] print(np.arange(1, 10)) # [1 2 3 4 5 6 7 8 9]
- 치환과 array 복사
- 치환 : 치환 제공자 변수의 주소를 대상자에게 전달해 같이 사용
↪ 두 변수는 연결되어 있음- np.copy(Array객체) : Array객체의 구조와 내부 값만 복사해서 사용
↪ 두 변수는 상호 독립적인 변수이다.a = np.array(1, 5) # (4,) 1차원 Vector # 치환 a1 = a # 객체 복사 a2 = np.copy(a) a[0] = 100 print(a1) # [100, 2, 3, 4] print(a2) # [1, 2, 3, 4]
- 인덱싱
arr[인덱스]
- 슬라이싱
arr[인덱스1 : 인덱스2]
- 전체 요소 순서 바꾸기
arr[::-1]a = np.array([1,2,3,4,5]) # 인덱싱 print(a[-4]) # 2 # 슬라이싱 print(a[1:4]) # [2 3 4] print(a[1:4:2]) # [2 4] print(a[1:]) # [2 3 4 5] # 요소 순서 바꾸기 print(a[::-1]) # [5 4 3 2 1]
- 인덱싱 특징
- 기본적으로 높은 차원에서의 인덱싱은 차원축소를 하는 역할을 한다.
- 인덱싱
- arr[0] : 0번째 행의 차원축소된 1차원 벡터를 추출
- arr[0][0] : 0번째 행인 1차원 벡터에서 0번째 요소를 추출
- arr[0, 0] : 0번째 행인 1차원 벡터에서 0번째 요소를 추출
- arr[[0]] : 0번째 행을 차원축소하지 않고 원본 그대로 추출a = np.array([[1,2,3],[4,5,6]]) # (2, 3) 2차원 Matrix print(a) # [[1 2 3] # [4 5 6]] print(a[0]) # [1 2 3] print(a[0][0]) print(arr[0, 0]) # 1 print(a[[0]]) # [[1 2 3]]
- 슬라이싱 특징
- 슬라이싱만 사용하면 차원축소가 되지 않는다.
- 슬라이싱
- arr[0:2] : 0행~1행까지 2차원 Matrix 추출
- arr[:1, :2] : 0행, 0~1열까지의 2차원 Matrix 추출a = np.array([[1,2,3],[4,5,6]]) # (2, 3) 2차원 Matrix print(arr[0:2]) # [[1 2 3] # [4 5 6]] print(arr[:1, :2]) # [[1 2]]
- 인덱싱 + 슬라이싱
- a[0, 0:2] : 0행의 차원축소된 1차원 벡터에서 0~1번째까지의 1차원 벡터 추출a = np.array([[1,2,3],[4,5,6]]) # (2, 3) 2차원 Matrix print(a[0, 0:2]) # [1 2]
- Sub Array란?
슬라이싱을 이용해 일부 데이터만 치환하여 만든 Array를 의미함a = np.array([[1,2,3],[4,5,6]]) a1 = a[:2, 1:] # 일부만 치환 (Sub Array) print(a1) # [[2 3] # [5 6]] a1[0,0] = 100 # 0행 0열의 값 수정 print(a) # a Array도 수정됨 # [[1 100 3] # [4 5 6]] print(a1) # [[100 3] # [5 6]]
- reshape()
- np.array의 형태를 변환한다.
- np.arange(1, 10).reshape(3, 3) : 1~10까지의 1차원 벡터를 3행3열 2차원 Matrix로 변경y = np.arange(5, 9).reshape(2, 2) # (4, ) 벡터 -> (2, 2) 행렬 array print(y, y.shape, y.size) # [[5 6] # [7 8]] # (2,2) # 4
- numpy 연산 특징
- Python 내장 함수보다 속도가 빠름
- numpy 연산 종류
- np.sum(), np.mean(), ....
- np.sum()
- 두 Array에서 동일한 인덱스 요소들에 더하기 연산 적용# product Sum : 동일한 인덱스에 있는 요소끼리 더하기 연산 print(x + y) print(np.add(x, y)) # => 동일한 결과 제공
- np.cumsum()
- 하나의 Array에서 인덱스가 높아질수록 누적합을 적용해 추출x = np.arange(5).reshape(2,2) print(np.cumsum(x)) # 누적합 # [ 1. 3. 6. 10.]
- np.substract()
- 두 Array에서 동일한 인덱스 요소들에 빼기 연산 적용# product Substract : 동일한 인덱스에 있는 요소끼리 빼기 연산 print(x - y) print(np.subtract(x, y))
- np.multiply()
- 두 Array에서 동일한 인덱스 요소들에 곱하기 연산 적용# product multiply : 동일한 인덱스에 있는 요소끼리 곱하기 연산 print(x * y) print(np.multiply(x, y))
- np.cumprod()
- 하나의 Array에서 인덱스가 높아질수록 누적곱을 적용해 추출x = np.arange(5).reshape(2,2) print(np.cumprod(x)) # 누적곱 # [ 1. 2. 6. 24.]
- np.divide()
- 두 Array에서 동일한 인덱스 요소들에 나누기 연산 적용# product divide : 동일한 인덱스에 있는 요소끼리 나누기 연산 print(x / y) print(np.divide(x, y))
- np.mean()
- 하나의 Array 내부 요소의 평균을 추출
- np.std()
- 하나의 Array 내부 요소의 표준편차를 추출print(np.mean(x)) print(np.std(x))
- np.dot()
- 두 Array에 내적 연산 적용
- 조건
- 첫번째 Array의 열개수와 두번째 Array의 행개수가 동일해야 한다.
ex) (N x M) Array와 (M x Z) Array 간의 행렬곱
- 1차원 x 1차원 행렬곱
v = np.array([9, 10]) # (2,) 1차원 벡터 w = np.array([11, 12]) # (2,) 1차원 벡터 print(v * w) # 요소별 곱셈 -> 1차원 벡터 # [99 120] print(np.dot(v, w)) # v[0]*w[0] + v[1]*w[1] -> 스칼라값 # 219
- 2차원 x 1차원 행렬곱
x = np.arange(5).reshape(2, 2) # (2,2) 2차원 Matrix v = np.array([9, 10]) # (2,) 1차원 벡터 print(np.dot(x, v)) # [ (x[0][0]*v[0] + x[0][1]*v[1]) (x[1][0]*v[0] + x[1][1]*v[1]) ] # [29. 67.]
- 2차원 x 2차원 행렬곱
x = np.arange(5).reshape(2, 2) # (2,2) 2차원 Matrix y = np.arange(5, 9).reshape(2, 2) # (2,2) 2차원 Matrix print(np.dot(x, y)) # 일반 matrix 간의 행렬곱과 같이 처리 # [[19. 22.] # [43. 50.]]
- np.unique()
- 하나의 Array 내부 요소의 중복을 제거한 결과 반환name1 = np.array(['tom', 'james', 'tom', 'oscar']) print(np.unique(name1)) # 중복 제거 # ['james' 'oscar' 'tom']
- np.union1d()
- 두개의 1차원 Array의 합집합 추출name1 = np.array(['tom', 'james', 'tom', 'oscar']) name2 = np.array(['tom', 'page', 'john']) print(np.union1d(name1, name2)) # 합집합 # ['james' 'john' 'oscar' 'page' 'tom']
- np.intersect1d()
- 두개의 1차원 Array의 합집합 추출name1 = np.array(['tom', 'james', 'tom', 'oscar']) name2 = np.array(['tom', 'page', 'john']) print(np.intersect1d(name1, name2)) # 교집합 # ['tom'] print(np.intersect1d(name1, name2, assume_unique=True)) # 교집합 (중복 허용) # ['tom' 'tom']
- transpose() or T
- 하나의 Array에서 행과 열을 바꾼다.x = np.arange(5).reshape(2, 2) # (2,2) 2차원 Matrix print(x.T) # [[1. 3.] # [2. 4.]] print(x.transpose()) # [[1. 3.] # [2. 4.]]
- Broadcast
- 크기가 다른 배열 간의 연산을 하면 작은 배열이 큰 배열의 크기를 자동으로 따라감x = np.arange(1, 10).reshape(3,3) # (3,3) 행렬 y = np.array([1,0,1]) # (3, ) print(x + y) # Broadcast 연산으로 (3, 3) 행렬 출력 # [[2 2 4] # [5 5 7] # [8 8 10]]
- **np.c[]**_
- np.c[2차원 Array객체, 추가할 1차원 벡터 열]_
: 2차원 Array 객체에 추가할 1차원 벡터를 열에 추가a1 = np.eye(3) # (3,3) 2차원 Matrix add_col = np.array(4) # (3,) 1차원 벡터 a2 = np.c_[a1, add_col] # [[1. 0. 0. 1.] # [0. 1. 0. 2.] # [0. 0. 1. 3.]]
- **np.r[]**_
- np.c[2차원 Array객체, 추가할 1차원 벡터 행]_
: 2차원 Array 객체에 추가할 1차원 벡터를 행에 추가a1 = np.eye(3) # (3,3) 2차원 Matrix add_col = np.array(4) # (3,) 1차원 벡터 a2 = np.r_[a1, add_col] # 행에 [1 2 3] 추가 # [[1. 0. 0.] # [0. 1. 0.] # [0. 0. 1.] # [1. 2. 3.]]
- reshape() 메소드 사용
- 1차원 벡터를 reshape() 메소드를 통해 2차원 Matrix로 확장a = np.array([1,2,3]) # (3,) 1차원 벡터 print(a.reshape(3, 1)) # (3, 1) 2차원 Matrix로 확장 # [[1] # [2] # [3]] print(a.reshape(1, 3)) # (1, 3) 2차원 Matrix로 확장 # [[1 2 3]]
- np.append() 메소드
- np.append(벡터, 추가할벡터, axis=0) : 새로운 1차원 벡터 추가
- axis 속성 : 0(행기준[Default]), 1(열기준)a = np.array([1,2,3]) # (3,) 1차원 벡터 b1 = np.append(a, [4,5], axis=0) # axis = 0(행기준[Default]), 1(열기준) print(b1) # [1 2 3 4 5]
- np.insert() 메소드
- np.insert(벡터, 인덱스, 추가할벡터, axis=0) : 인덱스에 새로운 1차원 벡터 추가a = np.array([1,2,3]) # (3,) 1차원 벡터 b1 = np.insert(a, 1, [4,5], axis=0) print(b1) # [1 4 5 2 3]
- np.delete() 메소드
- np.delete(벡터, 인덱스[list or 숫자형]) : 인덱스에 속한 데이터를 벡터에서 빼기a = np.array([1,2,3]) # (3,) 1차원 벡터 b1 = np.delete(a, 1) print(b1) # [1 3] b2 = np.delete(a, [1,2]) print(b2) # [1]
- np.append() 메소드
- np.append(벡터, 추가할벡터) : 차원 축소하여 마지막에 추가
- np.append(벡터, 추가할벡터, axis=0) : 차원 유지. 마지막 행에 추가
- np.append(벡터, 추가할벡터, axis=1) : 차원 유지. 마지막 열에 추가a = np.array([1,2,3]) # (3,) 1차원 벡터 b1 = np.append(a, [4,5,6]) print(b1) # [1 2 3 4 5 6] b1 = np.append(a, [4,5,6], axis=0) print(b1) # [[1 2 3] # [4 5 6]] b1 = np.append(a, [4], axis=1) print(b1) # [[1 2 3 4]]
- np.insert() 메소드
- np.insert(행렬, index, 새로운요소) : 차원 축소하여 추가
- np.insert(행렬, index, 새로운 요소, axis=0) : 차원 유지. 행 기준 처리
- np.insert(행렬, index, 새로운 요소, axis=1) : 차원 유지. 열 기준 처리aa = np.arange(1, 10).reshape(3,3) # (3,3) 2차원 행렬 print(np.insert(aa, 1, 99)) # [ 1 99 2 3 4 5 6 7 8 9] print(np.insert(aa, 1, 99, axis=0)) # [[ 1 2 3] # [99 99 99] # [ 4 5 6] # [ 7 8 9]] print(np.insert(aa, 1, 99, axis=1)) # [[ 1 99 2 3] # [ 4 99 5 6] # [ 7 99 8 9]]
- np.insert() 메소드
- np.insert(벡터, 인덱스, 추가할벡터, axis=0) : 인덱스에 새로운 1차원 벡터 추가a = np.array([1,2,3]) # (3,) 1차원 벡터 b1 = np.insert(a, 1, [4,5], axis=0) print(b1) # [1 4 5 2 3]
- np.delete() 메소드
- np.delete(벡터, 인덱스[list or 숫자형]) : 인덱스에 속한 데이터를 벡터에서 빼기a = np.array([1,2,3]) # (3,) 1차원 벡터 b1 = np.delete(a, 1) print(b1) # [1 3] b2 = np.delete(a, [1,2]) print(b2) # [1]
- **np.c[]**_
- np.c[2차원 Array객체, 추가할 1차원 벡터 열]_
: 2차원 Array 객체에 추가할 1차원 벡터를 열에 추가a1 = np.eye(3) # (3,3) 2차원 Matrix add_col = np.array(4) # (3,) 1차원 벡터 a2 = np.c_[a1, add_col] # [[1. 0. 0. 1.] # [0. 1. 0. 2.] # [0. 0. 1. 3.]]