꺼내먹는지식 준
numpy 본문
numpy는 코드로 방정식을 표현하고, 쉽게 계산할 수 있도록 도와준다.
2x1+2x2+x3=92x1−1x2+2x3=61x1−1x2+2x3=5
coefficient = [[2,2,1], [2,-1,2], [1, -1, 2]]
constant = [9, 6, 5]
numpy를 왜 쓸까?
1 누군가 구현해 놓은 matrix 관련 각종 수식 사용가능
2 python은 intepreter 언어라 느리기에, 이러한 고성능 과학 팩키지를 사용해야 한다.
--> 정확히 numpy가 list보다 더 빠른 이유는 다음과 같다. (https://checkwhoiam.tistory.com/94 참고)
1) list 는 다른 타입의 데이터들을 가질 수 있고, computation에 몇가지 과정을 더 거쳐야 하는 반면, numpy.ndarray는 메모리에 densely packed된 비슷한 타입의 데이터들이다.

부연 설명: 블로그에 사전 언급된 것과 같이 파이썬에서 -5 ~ 256 값은 특정 메모리 장소에 지정되어 있다. 즉, 해당 사이 값을 넣는다는 것은 해당 주소를 저장한다는 것과 같다. 접근 메모리 구조가 더 복잡하다보니 연산이 더 느리다. 물론 numpy는 하나의 타입만 저장하여 메모리 크기도 일정하다는 장점도 있다.
2) numpy는 한 task를 subtask로 알아서 나눠서 parall 하게 작동하기도 한다.
(예를 들면, np.dot()을 수행할 때, argument의 size가 크면 cpu core 전부를 쓰는 것을 확인할 수 있다.)
3) numpy는 C언어로 구현되어 있어서 더 빠르게 작동한다.
3 반복문이 필요없다.
Matrix, Vector와 같은 Array 연산의 사실상 표준
Numpy 사용법
1. Array 생성
np.array([1,2,3,4] , float)
--> array([1. , 4., 5., 8.])
numpy 는 np.array 함수로 ndarray(n-dimension) 를 생성한다.
* numpy에는 하나의 데이터 type만 배열에 넣을 수 있다. (numpy가 빠른이유 1))
shape: numpy array의 dimension 형태을 반환
dtype: 타입 반환
a = np.array([1,2,3,4] , float)
a.dtype
--> dtype('float64')
a.shape
(4, )
메모리 효율을 위해
dtype 을 선언할 때
dtype = np.float32 와 같이 메모리를 더 적게 소요하도록 선언해줄 수 있다.
reshpae: Array의 shape 크기 변경, 단 element 개수는 고정되어 있다.
a = np.array([1,2,3,4], [4,5,6,7])
a.reshape(1,8).shape
(1,8)
element 개수가 고정되어 있다보니, reshape 시 매개변수 한개는 정해주지 않아도 된다.
a.reshape(2,-1).shape
(2,4)
flatten: 다차원 array를 1차원으로 펴주는 역할
np.arange(30)
array([0,1,2,3,4, ... 29])
np.arange(0,5,0.5)
start point 0, end point 5, step size 0.5 (floating point 가 가능하다는 점 유념)
np.arange(30).reshape(5,6)
이런식으로도 사용 가능
np.array([1,2,3,4,5], [6,7,8,9,10], ...)
np.empty(shape=(10,), datatype = np.int8)
array([0 , 0 , 0 , ... ,0, 65, 1, 22])
empty는 shape 만 주어지면 비어있는 ndarray를 생성하는데, 문제는 memory를 initialize 하지 않아서 그 안에 이전에 저장되어 있던 값이 남아있을 수 있다.
즉 empty는 잘 안쓴다. 그냥 빈공간 잡자 할때 쓰는 정도..
a = np.aragne(30).reshape(5,6)
np.ones_like(a)
모든 element를 1로 채워준다.
np.zero(shape=(10,), datatype = np.int8)
0으로 초기화 생성
np.identity(n=3)
3 by 3 크기의 단위행렬 생성
np.eye(3)
3 by 3 크기의 단위행렬 생성
그러나,
eye는 column, row 각 크기 설정이 가능하고, 대각이 1로 설정되는 즉 시작하는 행의 위치를 정할 수 있다.
ex)
np.eye(3, 5, k=2) #k 가 2이므로 3번째 열부터 1 시작
array([0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0.]
[0., 0., 0., 0., 1.])
np.random.uniform(0,1,10).reshape(2,5) 0~ 1 까지의 값을 10개 균등분포에서 뽑아서 생성
array([0.23123 , 0. 545, 0. 12134, 0. 6543, 0. 43555]
[0.34333, 0.45434, 0.5452432, 0.11234, 0. 9184])
diag
대각 행렬 생성
2. indexing slicing
indexing
a = np.array([1,2,3], [4,5,6])
a[0,0]
--> 1
a[0][0]
--> 1
slicing
열과 행을 나눠서 slicing 이 가능하다.
a[:, 2:]
a[1, 1:3]
a[1:3]
--> indexing에서 [ , ]로 indexing 이 가능하다는 것을 기반으로 slicing 이 된다고 보면 된다.
a[:, ::2]
전체 row 에 대해 ( x: y: z --> start point x, end point y, stepsize z)
전체 column에 대해서 2씩 뛰어서 접근해라.
a[::2, ::3]
전체 row에 대해 2칸씩 뛰고, 전체 column에 대해 3칸씩 뛰어서 접근해라.
3. operation functions
a.sum()
모든 element 합
a.std()
모든 elemenet 의 std
a.sum(axis=1)
(2,3,4)의 shape ndarray가 있다고 할 때
axis 0 : 2 3D
axis 1: 3 row
axis 2: 4 column
ex) b = np.arange(30).reshape(3,5,2)
array([0,1], [2,3]...)
b[0][0][0] = 0
b[0][0][1] = 1
b.sum(axis=2)
array([1,5,9,13,17],...)
sum으로 차원수는 하나 떨어지고, 해당 axis 의 값들은 다 더해진다.
mathmatical function 들은 다 작동
exponential: exp, expm1, exp2, log, log10, power, sqrt ...
trigonometric: sin, cos, tan, acsin...
hyperbolic: sinh, cosh, tanh ...
b.mean() b.std() 등도 다 작동
심지어는 error function도 존재
concatenate
numpy array vstack
a = np.array([1,2,3])
b = np.array([4,5,6])
np.vstack ((a,b))
vertically concetenate
--> array([[1,2,3], [4,5,6]])
numpy array hstack
np.hstack((a,b)) * 매개변수는 (a,b) 이런 형태로 묶어줘야 한다.
array([[1,4], [2,5], [3,6]])
차원이 더 커지면 v, h stack 만으로는 불가능하다.
이때는 concatenate( (a,b), axis = n ) 으로 가능
사실상 concatenate 만 사용하고 vstack hstack은 사용하지 않아도 좋다.
*reshape 하지 않고, 축을 추가하는 방법
a = a[np.newaxis, :] 값은 그대로면서 축만 추가된다.
Transpose
a.T or a.transpose()
4.Array Operations
numpy 간 기본적 사칙연산
+, - , *(element-wise) , /, **, //
dot product
단순한 행렬 곱
broadcasting
scalar 값을 tensor 의 모든 element 에 적용
+, -, *, /, **, // 등 다 작동
예제
a = np.array([1,2,3], [4,5,6])
b = 2
a + b
--> array([[3,4,5], [6,7,8]])
vector, matrix 간의 연산도 지원한다.
이 경우
알아서 부족한 column, row 의 크기를 현재 존재하는 tensor 를 복재하여 맞춰준 후 연산.
ex)
a = np.arrange(1,13).reshape(4,3)
b = np.arage(10, 40, 10)
a + b
array([11,22,33], [14,25,36], [17,28,39], [20,31,42]) 모든 항에 a 가 복제되어 더해진 것 확인 가능
*timeit 으로 코드 동작 시간 확인 가능
for loop --> list comprehension --> numpy 순으로 빠르다.
5. Comparison
all , any
np.any(a>5) 하나만 조건을 만족해도 true
np.all(a>5) 모두 조건을 만족해야 true
numpy 의 배열 크기가 동일 할 때 비교 가능
a.shape
b.shape
--> (3,)
a > b
--> [True, False, False]
a == b
--> [False, True, True]
(a > b).any()
하나라도 true 면 true
--> True
np.logical_and(a>0, a<3)
두 조건 다 만족하는가?
np.logical_not(b)
b에 not 을 건 condition
np.logical_or(b,c)
or 을 건 컨디션
np.where(a>5)
index 값 반환
np.where(a>5, 3, 2)
True 면 3으로 대체, false 면 2로 대체
np.isnan(a)
np.NaN 이 element로 포함되어 있는가?
np.isinfinit(a)
학습 진행 중, 한없이 커지고 발산되는 경우에 memory의 크기를 넘어가면 잡아낼 수 있어야 한다.
그때 사용이 많이 된다.
argmax, argmin (np.argmax, np.argmin)
array내 최대값 또는 최소값의 index 반환
np.argmax(a, axis = 1)와 같이 axis 사용도 가능
6. boolean,fancy index
특정 조건이 맞을 때 해당 index 를 뽑아오는 방법
a = np.array([1,2,3,4,5,6])
a[ a>3 ]
array([4, 5, 6])
condition = a < 6
a[condition] 이렇게도 사용 가능
b = np.array([0,0,1,2])
a[b] == a.take(b)
array([1,1,2,3])
array 값을 index 처럼 사용 가능
3차 이상의 텐서에서도
a[b,c] 이런 형태로 사용 가능
* numpy 에도 load text, save text 기능이 있다.
a = np.loadtxt("./hajunaccount.txt")
b = np.savetxt("./hajunaccount.csv", a , fmt = ".%2e",delimiter = "," )
*유의점
a = np.arange(9).reshape((3,3))
[[0,1,2],
[3,4,5],
[6,7,8]]
a[:,1] vs a[:][1]
a[:,1]
a에서 전체 row에 접근해서 그 중 2번째 element들만 모아와라 라는 뜻이 된다.
즉, 1,4,7 을 모아오는 방법.
a[:][1]
a[:][1] 도 직관적으로 똑같이 동작할 것이라 생각했는데, 이렇게 선언하면 3,4,5 가 반환된다.
[:][1]는 기본적으로 전체 row를 반환하고, 그 중 2번째 row를 반환해라로 읽히는 즉, a[1] 와 차이가 없는 듯 하다.
Numpy 실전 꿀팁
np.dot(ndarray1, ndarray2.T)
ndarray1.dot(ndarray2)
모두 가능 (대부분 두가지 방법으로 사용 가능)
axis 햇갈리지 말자.
[[1,2,3,4,5], [6,7,8,9,10]]
shape: (2,5)
[1, 2] → 8
newaxis 사용법
K = np.random.normal(1, size = (3,5))
array([[ 0.39484584, -0.38801044, 0.16092178, 0.37693302, 1.74812049],
[-0.9199373 , -0.13282686, -2.05797436, -2.32262587, -0.67222107],
[-0.76677438, 0.66006324, 0.82848315, 1.22709894, -0.42932928]])
이 때 다음의 두개의 ndarray가 있다고 하자.
b = np.array(range(3))
c = np.array(range(5))
여기서 K 의 3이 뜻하는 것은 유저의 수이고, 5가 뜻하는 것은 각 유저별 5개 아이템에 대한 예측값이다.
그리고 b 는 각 유저별 편향 값이고 c는 각 아이템별 편향값이다.
b는 5, 5, 5 마다 b각각의 값을 더하고자하고 , c는 각 5개 각각에 c 각각 값을 더하고자 한다.
이때 newaxis 를 사용하면 된다.
b[:,np.newaxis]
array([[0],
[1],
[2]])
K + b[:, np.newaxis]
array([[ 0.39484584, -0.38801044, 0.16092178, 0.37693302, 1.74812049],
[ 0.0800627 , 0.86717314, -1.05797436, -1.32262587, 0.32777893],
[ 1.23322562, 2.66006324, 2.82848315, 3.22709894, 1.57067072]])
c[np.newaxis, :]
array([[0, 1, 2, 3, 4]])
K + c[np.newaxis, :]
array([[ 0.39484584, 0.61198956, 2.16092178, 3.37693302, 5.74812049],
[-0.9199373 , 0.86717314, -0.05797436, 0.67737413, 3.32777893],
[-0.76677438, 1.66006324, 2.82848315, 4.22709894, 3.57067072]])
이 경우는 사실 K + c 해도 결과는 동일하다.
'Python > 간단한 이해 글' 카테고리의 다른 글
Python Zip (0) | 2022.02.04 |
---|---|
Pandas (0) | 2022.01.18 |
String 및 변수, 함수 관련 (0) | 2022.01.17 |
Python List (0) | 2022.01.17 |
컴퓨터 기본 내용 정리, 파이썬 기본 내용 정리 (0) | 2022.01.17 |