Data science/Python

3. Numpy 한 페이지 요약

연금(Pension)술사 2019. 5. 13. 10:33

 

 

Numpy는 파이썬을 위한 과학 컴퓨팅 기본 패키지다.

리스트나 다른 배열과의 차이점은 넘파이 배열은 같은 타입만 요소를 가질 수 있다. 즉 동종(Homogenous type)만 요소로 있을 수 있다. 예를 들어, float32면, float32끼리만 요소로 가질 수 있고, int16이면 int16끼리만 가질 수 있다. 넘파이 배열은 보통 ndarray라고 부르는데, 앞서 언급한것처럼 내장 라이브러리에 array와는 다르다. 

 

Numpy객체들을 ndarray라고하는데, 이 객체가 가지고 있는 속성들은 다음과 같다.

- ndarray.ndim: 축의 개수를 출력(=차원의 수)

- ndarray.shape: 배열의 크기를 출력

- ndarray.size: 배열이 가지고 있는 총 요소의 수를 의미한다. 예를 들어 (3,2)의 모양을 가지고 있는 배열의 경우 6이 출력된다.

- ndarray.dtype: 데이터 타입 (형변환은 ndarray.astype()으로 변환)

- ndarray.itemsize: 배열의 각 요소의 바이트 단위의 사이즈. 즉 dtype에서 정의한 타입을 바이트 단위로 출력한다. 

float 64는 나누기 8을 하면되니, itemsize 8이 출력된다. 

 

 

 

 

Nd.arrayDtype: Nan(not a number)데이터타입은실수형(float)으로분류가된다. Integer바꿀, nan있으면못바꿀있다.

itemsize

retype.itemszie: 바이트 단위 사이즈 

 

int는 4byte.

 

long형은 8bytp여서 +_921경

3대는 int와 long의 구분이 없고, int의 자리수의 길이의 제한이 없어서... 그래서 대량 데이터는 최대길이의 숫자에 맞춰서 알아서 메모리를 할당하기 때문에, 공간의 낭비가 심하다.

numpy에서는 적당한 int32, int64 알아서 잡아서 할당해준다.

 

100도 안넘는데도 불구하고, 16가 나을것같은데 32를... 컴퓨터는 4바이트 단위로 짤라서 쓸 때, 속도가 가장빠른데, 32를 기준으로한다. 대부분의 언어도 그렇다.

 

 

dtype의 이해


항목 하나하는 64bit로 늘려서 만드는게 아니고, 두 항목을 64bit로 묶어서, 반환을 한다. 그래서 아래와 같이 이상한 값이 나온다.

32bit가 2개가 모여서 64bit가 되는거여서, 엉뚱한 값이 나온다. 타입의 용량이 부족하다고 맘대로 64bit로 늘리면 안된다.

왜냐하면 타입의 변경할 때, 실제 저장된 데이터의 구조(비트)가 변경되어서 반환이 되기 때문이다. 

Windows시스템의 특성 때문에, 그렇다. 이 는 숫자를 저장할 때, 비트 순서를 뒤바꾸어서 저장을 한다. 0+1을 결합해서 나오는데, 1과 0이 숫자가 뒤바뀌어서 나온다. 

 

예를 들어, 000000000 000000000.  000000000 000000000 <-0

000000000 000000000.  000000000 00000001 <- 1 이다.

이것을 합칠 때,  0다음에 1을 넣는게 아니라 1을 먼저 앞으로 두고, 0을 넣는다. (상위비트와 하위비트를 바꾸어서 저장하도록 되어있다) 만일 64비트 1을 저장한다면, 스텍의 크기 때문에, 먼저 저장한걸 나중에 저장하기 때문에,CPU구조 때문에 16bit->32bit 32비트씩 끊어서 저장을 하게되는데, 예를 순서대로 집어넣으면 반대로 나오기 때문에 뒤짚어서 저장을 한다. 

 

1
2
3
a.dtype = np.int64
# 원래32인 것을, int64로 바꾸면, 엉뚱한 값이 나온다
# 항목 하나 하나를 int64로 바꾸라는 말이 아니라, 전체 a를 int64로 바꾸라는 말로 된다.
cs
 
 
 
배열을 만들기

 

 

 

 

 

 

 


1. array을 통해 만들기.

 

arrary을 통해서 만들꺼면, array()함수 내에 시퀀스형을 넣어야한다. 시퀀스형은 예를 들어서, 튜플이나 리스트 등을 입력값으로 해야 넘파이객체가 만들어진다.

 

 

 

1
2
3
4
5
6
7
8
9
10
# array함수를 이용해서 만들기 
= np.array([2,3,4]) # 타입도 알아서 지정된다.
= np.array([2,3,5.4]) # type: float64
# Complex type
= np.array([[12], [34]), dtype = complex) # 복소수로 만든다.  1 + 0.j
# 기존의 배열을 가지고 만드는 경우
= np.array(c)
id(c), id(d) # id 주소가 서로 다름.
d2 = np.arrary(c, copy=False) # 새로운 배열을 만드는게 아니라, 주소를 그대로 쓸 수 있음.
 
cs

 

 

 

2.기본값 있는 배열 만들기

 

np.zeros(), np.ones(), np.empty()의 세가지 함수를 이용해서 만들 수 있다. 

np.array()는 안에 스퀀스형이 인자로 들어갔지만, 기본값이 있는 배열은 변수에 크기를 입력하면된다.

이렇게 만들어진 배열은 64비트인데, 타입 지정시 속도가 조금씩 차이가 난다.

타입을 지정할 때, 속도도 고려할 수 있는데, 정수는 4바이트 단위가 빨라서 32비트가 빠르다

실수는 64비트가 빠르다. 실수의 표현방법은 IEEE 954-9규약에 부동소수점 표현방법에 따라서 기본적으로, 실수는 64비트로 실수로 계산하게끔 만들어놓아서 32비트면 잘라서 해야되서 64비트가 빠르다.

1
2
3
4
5
6
7
8
9
10
11
np.ones((3,4))
# 정수는 4바이트가 빠르고
# 실수형은 64비트가 빠르다. 
 
np.empty((3,4))
np.arange(10# 1차원으로 반환
np.arange(5,10# 5부터 10미만
np.arage(5203# range(5,20,3)과 같다.
 
# 실수단위로 단위로, 개수를 지정하여 출력하기 위해서
np.linspace(029# 0부터 2까지 9개를 뽑아주세요. (0, 0.25, 0.5, 0.75....2) 마지막 값을 뽑아준다 
cs

3. 연속된 값을 갖는 배열 만들기.

numpy.arange(start, stop, step, dtype=None)

np.arange()을 이용해서 생성하는 방법이다. range()와 유사하게 사용할 수 있다.

또는 np.linespace(start, stop, num= 갯수) 을 이용해서도 출력할 수 있다.

1
2
3
import numpy as np
np.linspace(010, num=10)
np.linspace(02*3.14100
cs

 

 

 

 

배열의 차원 변경하기


np.random.random((3, 4))을 이용해서, (3,4) shape의 랜덤으로 배열을 만들 수 있다.

배열의 차원을 변경하는 함수들은 바로 반환되는게 아니라서, 다시 객체를 리턴값으로 받아주는 할당문이 있어야한다. 

 

np.ravel(): 차원이 모두 풀린 배열을 반환

1
2
= np.floor(10*np.random.random((3,4)))
a.ravel() # 차원이 풀린 1차원으로 배열을 나열한다.
cs

 

np.T: 전치행렬(transpose)을 반환

np.reshape(shape): (x,y) 의 shape을 가진 배열로 변경. 요소의 수(=size)가 같아야 한다. reshape(3,-1) 처럼 shape의 형태가 -1인 경우, 차원의 크기는 앞에 맞춰서 자동으로 계산이 된다. 

np.resize(shape): reshape이랑 같은 기능을 가진 메서드이다. 

 

resize와 reshape의 차이는?

reshape은 그 배열을 바꾸지 못하고, 리턴만해주는데, resize는 배열 자체를 변경한다.

reshape은 -1을 사용가능하지만, resize는 -1을 사용하지 못한다.

1
2
3
4
5
6
7
8
9
>>> import numpy as np
>>> a = np.arange(0,10)
>>> a.reshape(2,5)
>>> print(a)
[0 1 2 3 4 5 6 7 8 9]
>>> a.resize(2,5)
>>> print(a)
[[0 1 2 3 4]
 [5 6 7 8 9]]
cs

 

 

 

 

 

1
2
3
4
5
6
7
= np.arange(24).reshape(2,3,4# axis = 0 열임, 마지막 축은 '깊이가 2개인 행렬'
 
np.set_printoption(threshold=1000# 1000개까지만 출력하게 만듬
np.aragne(1010).reshape(10,101# 1000개가 나오고 10개가 가려지는게 아니라. 그보다 훨씬 더 많이 안보임
 
 
 
cs

Numpy 배열의 연산


행렬의 곱연산은 *이 아니라 dot 또는 @을 이용하여 계산한다. *으로 할 경우, 요소별 연산(element-wise)연산이 되기 때문에 다르다.

 

보통, 행렬을 연산할때, 피연산자의 shape이 다른 경우에는 브로드캐스팅 규칙이 적용되는데, 복합대행연산자(바로 대입하는 연산)를 이용할때는 타입이 같아야한다(라인 16~23). 복합대행연산자는 중간에 객체를 또 만들지 않고, 기존의 배열을 수정하기위해 사용된다. 
그러나, 아래의 예시처럼, a가 int형이고, b가 기본형(기본 dtype= float64)인 경우에는 풀어서 연산을 다시 할당받으면 사용 에러가나지 않고, int가 float32또는 float64의 형태로 상향형변환(upcasting)되지만, 복합대행연산자를 이용하여 할당받으려면, 객체의 타입이 그대로 int인 상태에서 연산이 float형을 받아야하기 때문에(=downcasting)이 되지 않아 에러가 발생한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
b**2 # 각 요소들을 제곱
a<35 # boolean으로 출력
np.sin(a) # 요소별로 사인값을 출력
 
 
# 곱연산
= np.array([[11], [13]])
= np.array([[20], [34]])
A*# Asterik을 쓰면안되고, 각 요소별로 곱이 나온다. 
 
# 행렬의 곱
np.dot(A,B)
A @ B 
 
# 복합대입연산자
= np.ones((2,3), dtype=int)
*= 3
 
= np.random.random((23)) # dtype = float64임.
 
= b + a # float64가 포함할 수 있지만
= b + a # int 을 포함할 수는 없지만, 풀어쓰면 가능하다. a+b을 더해서 실수를 만들어놓고, 추후에 a를 변환
+= b # 안된다. Down casting이 불가능하다. 1:1로 매핑하면서 계산을 해가는데, 동종모음이다보니깐 출력이 안됨
 
cs

 

 

Numpy Axis & Aggregation


넘파이 객체를 쓰다보면, 집계를 해야하는 경우가 있는데, 이럴 때 마다 ,축이 너무 헷갈려서 어느 축에 대해서 연산을 해야할지 모르는 경우가 발생한다. 이럴 때, 축에 대한 의미를 조금 더 공부할 필요가 있다. 

 

간단히 요약하면, axis = 0 은 로우를 하나로 보고 합치는 연산(row-wise)을 의미하고, aixs =1 은 컬럼을 하나로 봐서, 합치는 연산(column-wise)을 의미한다.

numpy의 axis을 어떤축을 합칠 것인지(collapses)를 말해주는 것이다. 

아래의 예시를 보면서 설명을 해보자.

 

1
2
3
4
5
6
>>> b = np.arange(12).reshape(3,4)
>>> print(b.shape)
>>> print(b)
>>> b.sum(axis=0# [12, 15, 18, 21]
>>> b.sum(axis=1# [6,22,38]
>>> b.sum(axis=2# Error
cs

 

 

위의 예를 보면 b의 shape이 (3, 4)인데, axis=0은 기본적으로 shape에서 가장 왼쪽에 있는 축을 의미한다고 생각하면 된다. 따라서 axis=0은 (,4)가 나와야한다고 생각하면 연산의 결과를 이해하기 쉽다. 따라서 요소가 4개가 나와야하니, 열(columns) 별로 연산을 한다고 생각하면 된다(라인4). 반대로, axis=1은 shape의 두번쨰인 (3,)이므로 3개가 나오면 된다고 생각하면되므로, 행별로 연산을 한다고 생각하면된다. 물론 ndim(차원의수)가 2개이니 axis 2는 불가능하다(에러, axis는 0축부터 시작하기 때문). 즉, axis 축이 가르키고있는 shape 숫자와 같은 결과가 출력된다. 

 

1
2
3
4
= np.aragne(24).reshape(2,3,4)
= sum(axis=0# dim 2. except 2 shape, aggregation result (3,4)
= sum(axis=1# dim 3. except 3 shape, aggregation result (2,4)
= sum(axis=2# dim 3, except 4 shape, aggregation result (2,3)
cs

 

 

 

범용함수 


 

1
2
3
4
5
6
7
# python general function
x1 = add(x1, x2)
x1 = np.arange(12).reshape(3,4)
x2 = np.arange(12).reshape(3,4)
x3 = x1 + x2 # 누산기를 통한 합계
add(x1, x2, x1)  # equivalent to 1 line (누산기X)
x1 += x2 # equivalent to 1 line (누산기X
cs

 

 

 

브로드케스팅 & 엘리먼트와이즈


브로드 케스팅 규칙은 '연산의 두 배열에 대한 후미 축의 크기가 동일한 크기이거나 둘 중 하나가 1이어야 한다는 것'이다. 예를 들어, (1, 3)과 (1,1)은 후미축의 크기가 동일하지는 않지만, 후미축이 1이므로 연산값을 동일하게 반복하여, 계산할 수 있다. 라인 6번~9번이 이에대한 설명이다. 그러나, 1) 반대로 후미축의 크기가 1이 아니거나, 2) 연산할 배열의 후미축이 다른경우는 라인 11번과같이 에러가 발생할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# element wise
= np.array([1,2,3])
= np.array([2,2,3])
+ b
 
# Braodcasting
= np.array([1,2,3]) 
= 2 # scala varible 
+ b
 
# Error
= np.array([1,2,3])
= np.array([1,2])
 
 
cs

 

아래의 예시에서도 1번~7번라인처럼 a.shape = (3, 3)이고 b가 (3, 3)이기 때문에 해당 연산이 가능하다. 또한 10번~라인부터처럼 a의 후미축의 크기가 1이고, b의 후미축의 크기가 1이 경우에도 해당 연산이 가능하다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
 
= np.array([[000],
              [123],
               [234]) # shape = (3,3)
= np.array([1,2,3]) # shape = (1,3)
+ b # last dimensions of both variables are equal
 
 
# Broadcasting is possible if dimension of any variabels is 1
from numpy import array, newaxis
= array([0,1,2,3,4])
= array([1,3,2]) 
print(a.shape, b.shape) # (5,), (3,)
print(a[:, newaxis].shape) (5,1)
a[:, newaxis] + b ; 
cs

 

 

 

인덱싱 & 슬라이싱


판다스의 인덱싱과 슬라이싱처럼, 넘파이에서 인덱싱과 슬라이싱이 가능하다. 이를 통해, 할 수 있는 것은, 배열에서의 부분집합을 추출하는 것이다. 리스트와 마찬가지 인덱싱은 0번부터 인덱스가 시작한다. 음수를 적용한 슬라이싱/인덱싱 도 리스트와 동일하다. 

 

차원별 인덱스하는 방법이 조금씩 다른데, 1차원에서는  np.array[0축], 2차원에서는 np.arrary[1축, 0축], 3차원에서는 np.array[2축, 1축, 0축]으로 지정하여 추출할 수 있다. 

 

한편, 축인덱스를 생략해서 출력할 수 있는데, 예들 들어서, 차원의 수가 3이경우에, a[-1] 과 같이하면, a[-1::]와 동일하다.

1
2
3
4
5
6
>>> import numpy as np
>>> a = np.arange(24).reshape(2,3,4)
>>> a[-1::]
array([[[12131415],
        [16171819],
        [20212223]]])
cs

 

'...'을 이용해서 인덱스를 생략할수도 있다.  

1
2
3
4
5
6
# a[:,:,2] vs  a[::2] 비교
>>> print(a)
a[0::] # 2축에 대해서 시작이 0, 맨 뒤까지 뽑겠단 코드
a[::2# 2추게 대해서, 시작이 0, 2step 단위로
a[0,:,:] # 2축에 대해서 0번인덱스이고 모든 인덱스를 포함한 서브셋을 출력
a[0,...]
cs

 

 

 

Stack

 


축에 대한 이해가 필요하다.  종류로는 hstack, vstack, dstack 이 있다. hstack은 옆으로 쌓는 것이기 때문에 0축의 개수가 늘어나며, vstack은 아래에 row을 하나 더 붙이는 것이기에, 1축의 개수가 늘어난다. dstack은 dimension이 늘어나는것인데, (3, 4)짜리 2개를 nstack하면 (3, 3, 4)의 모양의 배열이 출력된다.

 

vstack:

hstack

nstack: 첫 번째 배열의 0번과 두 번째 배열의 0번을 조합하여 하나의 마지막 축에 해당하는 요소를 하나 더 늘린다.

stack((넘파이배열, 넘파이배열, 넘파이배열...), axis = 축): axis에 따라 범용으로 사용

축에 대한 파라미터가 없으면, 0축으로 합쳐진다.  (3,4) shape인 2개의 넘파이가 0축을 기준으로 합쳐지면 (2,3,4)가 된다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# hstack: 배열을 옆에 추가하는 방식. horizontal 옆으로 쌓는다
= np.arange(3)
= np.arange(3,6)
 
np.hstack((a,b)) #
print(np.hstack((a,b)).shape) # (6,)
# vstack
np.vstack((a,b)) 
print(np.vstack((a,b)).shape) # (2,3)
# dstack: 깊이별로 쌓는다. 차원이 하나 증가한다. '[]' 대괄호가 증가한다
np.dstack((a,b))
print(np.dstack((a,b)).shape) # (1,3,2)
 
# newaxis
# 1차원이 newaxis을하면 2차원이 되고, 
# 2차원이 newaxis을하면 3차원이 된다.
= a[:, np.newaxis]
= b[:, np.newaxis]
np.hstack((a,b))
cs

 

 

dstack은 같은 배열에서, 0축이 2배로 증가하는 것과 같다. 

 또한, 축에 숫자를 넣을 때, 축의 숫자는 shape에서 순서가 변하는 것과 같다. (3, 4)의 2개의 배열이 합쳐질 때, axis = 0이면, shape의 첫요소 2가 되어서 (2,3,4)이며, axis =1이면 (3,2,4)가 되며, axis =2 이면 (3,4,2)가 된다.

 

r_(), c()

r_(): R에서의 rbind와 유사하다.

c_(): R에서의 cbind와 유사하다 .

 
1
2
3
4
5
6
7
8
9
10
11
import numpy as np
= np.array((1,2,3,4)) # shape (4,)
= np.array((5,6,7,8))
= np.array((9,10,11,12))
 
# r_()
np.r_[a,b,c] # R bind와 유사하게, 길이를 늘려준다. shape (12,)
np.r_[[a],[b],[c]] # 리스트로 구분하고 싶다면..
np.vstack((a,b,c)) # vstack과 동일
print(a.shape, b.shape, c.shape) # (4,) 을 vstack하면 (3,4)
print(np.vstack((a,b,c)).shape) # (3,4)
cs

 

 

Split

split은 array 배열을 받아서, 리스트로 반환한다.split은 n개로 나누어서 나머지가 0이 아니면 에러가 나온다.

  • hsplit: 0축을 기준으로 나누어 반환함. hsplit 은 split(~, axis=1)과 같다. 두 번째 shape을 기준으로 잘라서 나온다. 2, 3, 4를 자르면 (2,1,4)가 출력됨.
  • vsplit: 가장 맨 앞의 shape 기준으로 나누어서 반환함. (3, 4)을 split하면 (1,4)가 요소인 배열이 나옴. split(~, axis=0). (2,3,4)을 2로 나누면 (1,2,4)가 나온다.
1
2
3
4
5
6
7
8
# Split
= np.arange(12).reshape(3,4)
print(a)
 
# np.vsplit
a_vsplit = np.vsplit(a, 3# (3,4) shape짜리를 vertical로 붙여준다.
print('shape:', a_vsplit[0].shape) # (1,4)가 3개, (4,)이 3개가 아님.
 
# np.hsplit 
a_hsplit = np.hsplit(a, 4) # (3,4) shape짜리를 4개로 쪼개어
print('shape:', a_hsplit[0].shape) # (3,1)이 4개
cs

 

3차원으로 확장하면, 다음과 같다.

 

튜플형식으로 나누자고하면, 다음과같다

예를 들어, hsplit (2,5,6)은 0~1까지 하나, 2~4까지하나 5~6에서하나 6부터 끝까지 출력된다.

 

 

  • Numpy.array_split(array, num_section, axis = 0)

 

 

split은 나눠 떨어지지 않으면, 오류가 나온다. 그러나, 나눠 떨어지지 않는 정수를 이용하여, 배열을 분리한다.

SQL에의 NTILE처럼, n개로 나눈후에 나눈 나머지는 앞에서부터 순차적으로 가져간다. 예를 들어 13개를 3개로 나누면, 5, 4, 4개로 나누어진다.

 

 

 

 

 

데이터복사(View, Copy)


Numpy.view() = 동일 주소값의 데이터 + 형태만 다른 배열 객체

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

같은 데이터를 참조하지만, 다른 shape을 가지는 객체를 의미한다. 데이터 자체는 처음 뷰를 생성한 객체가 가지고 있다. 예를 들어 a를 통해서 뷰를 생성한 경우에는 shape은 다르게 가질 수 있다. 데이터의 부분집합을 추출할 때, view을 뽑을지, copy로 뽑을지 고민해야한다. copy와 view의 차이점은 copy는 완전히 메모리상에 완전히 새로운 데이터를 갖는다 (주소값이 다르다). 뷰는 메모리상에 같은 데이터를 참조를 하지만, 다만 shape가 다르기 때문에, 읽는 순서가 달라질 뿐이다. (= 깊은 복사 , copy) 

뷰를 통한 shape은 다르게 가질 수 있다.

 

 

파이썬이 [1, 2, 3] 을 저장할 때, 1은 따로 저장, 2도 따로저장, 3도 따로 저장한다음에, 1의 주소 2의 주소 3의주소 이렇게 연결자료구조로 만든다. 그러나 numpy 차원 배열을 저장할 때는 np.array([1,2,3], type = int32)처럼 숫자가 크기를 고려해서 저장하기 때문에, [1][2][3] 연결해서 32비트씩을 가져서 한개의 값을 인덱싱을할 때 바로 알 수 있다. 첫 주소만 알면 나머지는 변수의 자료의 크기만큼만 건너 뛰면되기 때문에, 바로 알 수 있다.

 

인덱싱할 때, 배열로 뽑아올 경우는 copy가 온다.

 

 

 

고급인덱싱를 이용한 인덱싱


 

1
2
3
4
5
6
7
8
# 리스트 배열로 인덱싱
= np.arange(12)**2
ind = np.array([1,1,3,8,5])
a[ind] # array([ 1,  1,  9, 64, 25])
 
# 다차원으로 만들기
= np.array([[3,4], [9,7]])
a[j]
cs

 

다차원 인덱싱


인덱싱 자체가 여라차원인 경우를 의미한다. X[Y, Z] 이러한 인덱싱에,  Y도 다차원, Z도 다차원을 사용하는 경우를 의미한다.

이러한 인덱싱은 X[Y,:]을 우선 계산한다음에, X[Y. :]에 Z인덱싱을 적용한다. 아래의 예시를 보면 이해가 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 다차원 인덱싱
import numpy as np
= np.arange(12).reshape(3,4)
= np.array([[0,1], [1,2]])
= np.array([[2,1], [3,3]])
 
 
a[i,:] 
# array([[[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7]],
 
#        [[ 4,  5,  6,  7],
#         [ 8,  9, 10, 11]]])
# 위의 조건에서 j을 적용한다. 즉 a[i,:]에서 2번째 컬럼을 찾고, 1번쨰 컬럼, 
3번쨰 컬럼, 3번째 컬럼을 찾는다
 
a[i,j]
# array([[ 2,  5],
#        [ 7, 11]])
cs

 

 

최대값 검색

 

 

 

 

 

 


np.argmax : 최대값을 갖는 인덱스를 찾는다.

 

 

 

 

 

 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 배열 인덱스를 이용한 최대값 검색
import numpy as np
data = np.sin(np.arange(20)).reshape(5,4)
# array([[ 0.        ,  0.84147098,  0.90929743,  0.14112001],
#        [-0.7568025 , -0.95892427, -0.2794155 ,  0.6569866 ],
#        [ 0.98935825,  0.41211849, -0.54402111, -0.99999021],
#        [-0.53657292,  0.42016704,  0.99060736,  0.65028784],
#        [-0.28790332, -0.96139749, -0.75098725,  0.14987721]])
 
ind = data.argmax(axis=0)
# array([2, 0, 3, 1])
 
# 이렇게 복잡하게 해야하는데.
data_max = data[ind, range(data.shape[1])]
range(data.shape[1])
 
# 아래의 경우처럼 바로 찾는 것도 가능하다.
data.max(axis=0)
cs

 

 

 

인덱싱을 이용한 값 변경


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# --인덱스를 이용한 값 변경--
import numpy as np
 
= np.arange(5)
a[[1,3,4]] = 0 # 인덱스를 이용한 값 변경
# a[1,2] # 1,2 을 넣으면 a를 2차원으로 인식해서 shape 1,2 인덱스를 찾는다.
a[[1,2]] # [1,2] 을 넣어야한다.
 
= np.arange(5)
# [0 1 2 3 4]
 
 
a[[0,0,2]] = [10,20,30# 0번째 인덱스는 20이 할당
a[[0,0,2]] += 1 # 가장 마지막 값만 변경된다.  #[1,1,3,3,4]
# a[[0,2]] 만 실행이 된다.
cs

 

 

 

논리 배열 인덱스를 이용한 인덱싱


 

1
2
3
4
5
# 부울 배열을 이용한 인덱싱 (True / False을 이용한 인덱싱)
= np.arange(20).reshape((4,5))
= a% 2 ==0 # 나누기 2가 0인 경우만 true가 반환하다. 
a[b] = a[b] **2 # 재할당도 가능하다
a[b] = 0 
cs

 

 

ix_()


1
2
3
4
5
6
7
8
9
10
# ix_() 
= np.array([2,3,4,5])
= np.array([8,5,4])
ax, bx = np.ix_(a,b) # N개의 1차원 시퀀스를 입력 받아 추출해서 ,
각각 N차원인 N 개의 출력을 반환
 
# (array([[2],
#        [3],
#        [4],
#        [5]]), array([[8, 5, 4]]))
 
cs

 

 

 

 

리듀서(Reducer)


집계하는 함수를 모두 리듀서라고 부름(reducer). 매개변수로 함수와 값들을 입력받아 각 요소들에 함수를 적용하고 하나의 결과의 값을 반환하는 함수

1
2
3
4
5
6
7
8
9
10
# 집계하는 함수를 모두 리듀서라고 부름(reducer)
def func_reduce(*vectors, func=np.add):
    vs = np.ix_(*vectors)
    r = func.identity # 항등원을 계산
    print(vs)
    for v in vs:
        r = func(r, v)
    return r
 
func_reduce(a,b)
cs

 

배열 조작


- 행렬 곱: @ 또는 dot

- 역행렬 np.linalg.inv(x)

- 특이값 분해: u, s, vh = np.linalg.svd(A)

- 고유값, 고유벡터 = w, v = np.linalg.eig(x)

 

원본행렬 A(m, n)를 쪼개서 U라는 행렬과 sigma라는 대각행렬 V(t) ㅍ

(m, m) (m, n), (n, n) 이 반환. 원본행렬을 가장 잘 표현할 수 있는 왼쪽상단. 오른쪽 하단으로 갈 수록 원본행렬을 표현하기에는 대표적이지 않은 값일 수 있음. Sigma 행렬을 그래서 다 사용하지 않고, 일부를 잘라서 사용한다.

원본행렬이 null 이 너무 많은 경우, 특이값 분해를 한 다음에, 다시 원본행렬을 만들면 null이 채워지는 경우가 있다.

 

선형 연립방정식


역행렬을 구하려면 정방행렬을 만들어야하는데, 행의수가 열의수가 훨씬 많을 때, left pseudo inverse 을 구한다.

 

히스토그램 

히스토그램 구간내의 값만 알려준다.

 

 

 

dtype


unsigned int8

np.fromstring()

 

 

 


np.power: np.power은 흔히 멱급수를 따른다고하는 식으로 반환한다. 쉽게설명하면 np.power(a, b)은 a**b와 같다.

np.power(10, 2) # 100
np.power(3, 2)  # 9
np.power(9, 0.5) # 3.0

First array elements raised to powers from second array, element-wise.

Raise each base in x1 to the positionally-corresponding power in x2. x1 and x2 must be broadcastable to the same shape. Note that an integer type raised to a negative integer power will raise a ValueError.

 

Parametersx1array_like

The bases.

x2array_like

The exponents. If x1.shape != x2.shape, they must be broadcastable to a common shape (which becomes the shape of the output).

반응형