220919 Day17

유예지·2022년 9월 19일

2. numpy 내장함수

(1) Numpy 내장함수를 이용하여 array 만들기

arange / linspace / zeros / ones / empty / full / tile / ~_like

* linspace(start, stop, numbers of element)

lin : line

>>> import numpy as np
	np.linspace(1 ,10, 10)
array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.])

>>> np.linspace(0, 1, 6)
array([0. , 0.2, 0.4, 0.6, 0.8, 1. ])

>>> np.linspace(1 ,9, 5)
array([1., 3., 5., 7., 9.])

>>> np.linspace(1 ,9, 5, endpoint=False)
array([1. , 2.6, 4.2, 5.8, 7.4])

* np.ones(shape [, dtype, order])

>>> np.ones((2,3))    #(2,3) -> tuple 형태, 2행 3열
array([[1., 1., 1.],
       [1., 1., 1.]])
       
>>> np.ones((2,3), dtype = "int16")
array([[1, 1, 1],
       [1, 1, 1]], dtype=int16)
       
>>> np.ones((3,3), int)
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]])

* np.zeros(shape [, dtype, order])

>>> np.zeros((2,3))
array([[0., 0., 0.],
       [0., 0., 0.]])
       
#sparse matrix (희소행렬) : 행렬 안의 많은 항들이 '0'으로 되어있는 행렬
#10x10 = 대부분 0
#3행 3열 부분 1, 5행 6열 부분 1

>>> arr = np.zeros((10, 10))
    arr
    arr[3,3] = 1
    arr[5,6] = 1
    arr
array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
  • 모든 원소가 3인 10X10 array
>>> a = np.ones((10, 10))
    a*3

>>> np.full((10,10), 3)   #10행 10열 만큼을 3으로 채운다

* np.identity(), np.eye()

#단위행렬 - np.identity() 는 정사각행렬이 정해져있다
>>> np.identity(3)    #3행 3열, 행과 열의 숫자가 같은 자리에만(대각선자리) '1' 값이 있다
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
       
#np.identity(3)과 np.eye(3)은 같다
>>> np.eye(3)       

>>> np.eye(3, 2)    #3행 2열
array([[1., 0.],
       [0., 1.],
       [0., 0.]])

* np.tile(), np.empty()

>>> a = np.array([0,1,2])
    np.tile(a, 2)   #a를 2번 반복
    np.tile(a, (3, 2))   #a를 (3행 2열)번 반복

>>> np.empty((2, 3))    #null에 해당하는 주소값, 초기화 안함
array([[1., 0., 0.],
       [1., 0., 0.]])

(2) _like() 함수로 배열 만들기

zeros_like( ) / ones_like( ) / empty_like( ) / full_like( )

* zeros_like() : 형태와 데이터 타입을 유지하면서 '0' 으로 채움

>>> a = np.arange(6).reshape(2,3)
	a
	np.zeros_like(a)
array([[0, 0, 0],
       [0, 0, 0]])
       
>>> b = np.arange(3, dtype=float)
	print(b)
	b.dtype
[0. 1. 2.]
dtype('float64')

>>> np.zeros_like(b)
array([0., 0., 0.])

* ones_like() : 형태와 데이터 타입을 유지하면서 '1' 로 채움

>>> a = np.arange(6).reshape(2,3)
	np.ones_like(a)
array([[1, 1, 1],
       [1, 1, 1]])
       
>>> b = np.arange(3, dtype=float)
	np.ones_like(b)
array([1., 1., 1.])    

* full_like(), empty_like()

#full_like() : 형태와 데이터 타입을 유지하면서 '입력한 수' 로 채움
>>> np.full_like(a, 3)
array([[3, 3, 3],
       [3, 3, 3]])
       
>>> np.full_like(b, .31)
array([0.31, 0.31, 0.31])

>>> np.empty_like(a)
>>> np.empty_like(b)

(3) copy 의 두가지 방법

기본 배열로부터 '새로운' 배열을 생성하기 위해서는 'copy 함수'를 이용해 명시적으로 사용해야 한다
copy 함수로 복사한 배열은 원본 배열과 완전히 다른 '새로운 객체' 이다
'slice, indexing' 은 새로운 객체가 아닌 기존 배열의 뷰 (View : id를 공유하여 본다)
반환한 배열의 값을 변경하면 원본 배열이 변경된다

* list copy

>>> a = [1,2,3,4]
    b = a
    b    #a의 주솟값(id)이 b에 복사됨
[1, 2, 3, 4]

>>> c = a.copy()
	c
[1, 2, 3, 4]

>>> import copy
	d = copy.copy(a)
    d
[1, 2, 3, 4]

>>> b[0] = 100   #리스트 내의 값 수정
	b
[100, 2, 3, 4]    

>>> print(a)
	print(c)
    print(d)
[100, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]    

>>> print(id(a))
    print(id(b))
    print(id(c))
    print(id(d))
#a와 b는 id가 동일하고, c와 d는 a,b와는 완전히 다르다(c와 d 서로의 id도 다르다)    

* array copy

>>> a = np.array([1,2,3,4])
	b = a
    b
array([1, 2, 3, 4])

>>> c = a.copy()
	c
array([1, 2, 3, 4])

>>> import copy
	d = copy.copy(a)
    d
array([1, 2, 3, 4])

>>> b[0] = 100
	b
array([100, 2, 3, 4])    

>>> print(a)
	print(c)
    print(d)
[100   2   3   4]
[1 2 3 4]
[1 2 3 4]

>>> print(id(a))
    print(id(b))
    print(id(c))
    print(id(d))
#a와 b는 id가 동일하고, c와 d는 a,b와는 완전히 다르다(c와 d 서로의 id도 다르다)    

3. 배열의 결합, 분리, 형태변환

(1) 배열의 결합 : stack

stack : FILO (first in last out), 선착순의 반대
hstack / vstack / dstack / concatenate

#[0, 10, 20, 30, 40, 50, 60, 70, 80, 90] 출력
>>> a = np.arange(10)*10
    b = np.arange(10)*20
    print(a)
    print(b)
[ 0 10 20 30 40 50 60 70 80 90]
[  0  20  40  60  80 100 120 140 160 180]   

>>> np.vstack((a, b))   #vstack 에서의 'v' : vertical (세로로 합한다)
array([[  0,  10,  20,  30,  40,  50,  60,  70,  80,  90],
       [  0,  20,  40,  60,  80, 100, 120, 140, 160, 180]])
#2행 10열 이 만들어졌다 

>>> np.hstack((a, b))   #hstack 에서의 'h' : horizental (가로로 합한다)
array([  0,  10,  20,  30,  40,  50,  60,  70,  80,  90,   0,  20,  40,
        60,  80, 100, 120, 140, 160, 180])
#1행 20열 이 만들어졌다 
>>> np.hstack((a, b)).shape
(20,)
>>> a = np.array([[1], [2], [3]])
	print(a.shape)
	a
(3, 1)   #3행 1열 -> 대괄호 2개, 2차원 배열
array([[1],
       [2],
       [3]])
       
>>> b = np.array([[1], [2], [3]])
	b       

>>> np.hstack((a, b))
array([[1, 1],
       [2, 2],
       [3, 3]])

>>> np.dstack((a, b))   #dstack : 2차원 배열의 결합 -> 3차원 배열(?)
array([[[1, 1]],

       [[2, 2]],

       [[3, 3]]])

(2) 배열의 분리 : spliting

분리한 결과물이 어떻게 나오는지에 따라 -> 수평분리(hsplit) 와 수직분리(vsplit)

>>> a = np.arange(32).reshape(4,8)
	a
array([[ 0,  1,  2,  3,  4,  5,  6,  7],
       [ 8,  9, 10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29, 30, 31]])    

#hsplit 수평분리
>>> np.hsplit(a, 2)
[array([[ 0,  1,  2,  3],
        [ 8,  9, 10, 11],
        [16, 17, 18, 19],
        [24, 25, 26, 27]]),
 array([[ 4,  5,  6,  7],
        [12, 13, 14, 15],
        [20, 21, 22, 23],
        [28, 29, 30, 31]])]
        
>>> np.hsplit(a, 4)        

#vsplit 수직분리
>>> np.vsplit(a, 2)
[array([[ 0,  1,  2,  3,  4,  5,  6,  7],
        [ 8,  9, 10, 11, 12, 13, 14, 15]]),
 array([[16, 17, 18, 19, 20, 21, 22, 23],
        [24, 25, 26, 27, 28, 29, 30, 31]])]

(3) 형태변환 (numpy의 shape 변경 함수)

reshape / flatten / ravel

>>> a = np.arange(32).reshape(4,8)
	a

>>> print(a.shape)
	print(a.size)
    
#flatten() : 단지 복사한 값을 출력한다
>>> a.flatten()
	#a.flatten().shape
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31])    
       
#ravel()
>>> a.ravel()
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31])
       
#flatten과 ravel의 차이점
>>> b = a.flatten()
	c = a.ravel()

>>> b[3] = 30
	print(b)
>>> print(a)

>>> c[3] = 30
	print(c)
>>> print(a)    #ravel로 값을 변경한 것은 원래 배열 값에도 적용되어있다    
  • transpose : 행과 열의 위치를 바꾼다, 행렬의 곱셈을 가능하게 해준다
>>> a = np.arange(1, 7).reshape(3, 2)
	a
array([[1, 2],
       [3, 4],
       [5, 6]])

>>> np.transpose(a)
array([[1, 3, 5],
       [2, 4, 6]])
       
>>> a = np.array([1,2,3])
    b = np.array([4,5,6])
    c = np.vstack((a, b))
    c       
array([[1, 2, 3],
       [4, 5, 6]])

>>> np.vsplit(c, 2)
[array([[1, 2, 3]]), array([[4, 5, 6]])]

4. 비교 comparison, 정렬 sort, 인덱싱 indexing

(1) 비교

>>> a = np.array([1,2,3,4])
    b = np.array([1,3,4,2])
    a == b
array([ True, False, False, False])   

>>> a > 2
array([False, False,  True,  True])

>>> a[a>2]
array([3, 4])

(2) 정렬

#np.sort() 함수와 객체.sort()의 차이
>>> a = np.array([1,3,4,2])
	a
    
>>> np.sort(a)
array([1, 2, 3, 4])    #그저 정렬해서 보여주기만 한 것 뿐 (View)

>>> a
array([1, 3, 4, 2])    #np.sort(a) 를 했지만 a는 여전히 그대로 이다

>>> a.sort()   #.sort() 는 메소드
	a
array([1, 2, 3, 4])   #배열 자체를 정렬

#역순으로 정렬
>>> a[ : :-1]    #정렬한 후 뒤에서 읽어옴
array([4, 3, 2, 1])
>>> a
array([1, 2, 3, 4])

#축을 지정하여 정렬
>>> x = np.array([[2,1,6], [0,7,4], [5,3,2]])
	x
array([[2, 1, 6],
       [0, 7, 4],
       [5, 3, 2]])

>>> np.sort(x)    #각 행을 정렬
array([[1, 2, 6],
       [0, 4, 7],
       [2, 3, 5]])

#'axis = 0' : 행은 신경쓰지 않고 '열'을 기준으로만 정렬 (row - wise)
>>> np.sort(x, axis = 0)
array([[0, 1, 2],
       [2, 3, 4],
       [5, 7, 6]])

#'axis = 1' : '행'을 기준으로만 정렬 (coloum - wise)
>>> np.sort(x, axis = 1)
array([[1, 2, 6],
       [0, 4, 7],
       [2, 3, 5]])

(3) 인덱싱 : array[행의 인덱스 번호, 열의 인덱스 번호]

#6X6 array 를 만들어보자
#array([[ 0,  1,  2,  3,  4,  5],
       [10, 11, 12, 13, 14, 15],
       [20, 21, 22, 23, 24, 25],
       [30, 31, 32, 33, 34, 35],
       [40, 41, 42, 43, 44, 45],
       [50, 51, 52, 53, 54, 55]])
       
#방법1
>>> a = np.arange(6)
    b = np.arange(6) + 10
    c = np.arange(6) + 20
    d = np.arange(6) + 30
    e = np.arange(6) + 40
    f = np.arange(6) + 50

    np.vstack((a,b,c,d,e,f))

#방법2
>>> a = np.array([0,1,2,3,4,5])
    b = np.array([[0],[10],[20],[30],[40],[50]])
    a+b
    
#방법3
>>> a = np.arange(6)
    array = a.copy()
    for i in range(5):
        i += 1
        array = np.vstack((array, a+10*i))
    array
    
#방법4
>>> a = np.arange(100).reshape(10,10)
    a = a[0:6:1,0:6:1]
    a 

* 슬라이싱 slicing : var[lower:uppper:step]

slice 한 것은 복사품이 아니라, 원본의 참조이다

>>> a = np.arange(100).reshape(10,10)
    a = a[0:6:1,0:6:1]
    a 
    
#[2, 12, 22, 32, 42, 52] 출력
>>> a[ : , 2]    

#[3, 4]
>>> a[0, 3:5]
>>> a[-6, 3:5]

#[[44, 45], [54, 55]]
>>> a[4: , 4: ]

#[[20, 22, 24],  [40, 42, 44]]
>>> a[2:5:2, :5:2]

* Fancy indexing

정수 배열을 indexer로 사용해서 Indexing하는 방법

#fancy indexing.position
>>> a = np.arange(8)*10
	a
array([ 0, 10, 20, 30, 40, 50, 60, 70])

>>> a[[1, 2, -3]]
array([10, 20, 50])

>>> indices = [1, 2, -3]
    a[indices]
array([10, 20, 50])    

#fancy indexing.boolen
>>> mask = [False, True, True, False, False, True, False, False]
	a[mask]
array([10, 20, 50])

>>> mask = np.array([0, 1, 1, 0, 0, 1, 0, 0], dtype = bool)
	mask
array([False,  True,  True, False, False,  True, False, False])

>>> a[mask]
array([10, 20, 50])

#2차원 팬시 인덱싱
>>> a = np.arange(100).reshape(10,10)
    a = a[0:6:1,0:6:1]
    a

>>> [a[0, 1], a[1, 2], a[2, 0], a[2, 3]]
[1, 12, 20, 23]

>>> a[[0,1,2,2], [1,2,0,3]]
array([ 1, 12, 20, 23])

#5X5의 배열을 만들고 ..
>>> a = np.arange(25).reshape(5,5)
	a
>>> a[[0,1,2,3], [1,2,3,4]]
array([ 1,  7, 13, 19])

5. Array Calculation (= Computation) by Universal Functions

* 수학함수 : sum, prod, min, max, argmin, argmax

* 통계함수 : mean, std, var

* 진리값 : any, all

>>> a = np.array([[1,2,3], [4,5,6]])
	a
    
>>> sum(a)
array([5, 7, 9])

>>> print(np.sum(a))
	print(np.sum(a, axis = 0))
	print(np.sum(a, axis = 1))
21
[5 7 9]
[ 6 15]    

>>> a = np.array([1,2,3])
    b = np.array([4,5,6])
    print(a+b)
    print(a**b)
[5 7 9]
[  1  32 729]

>>> np.sin(a)   #각각의 요소에 sin 함수 적용
array([0.84147098, 0.90929743, 0.14112001])

>>> print(np.max(a))
	print(np.min(a))
    
#argmin(), argmax() -> 최소값과 최대값일 때의 인덱스를 출력해줌
>>> a = np.array([[1,2,3], [4,5,6]])
    print(a)
    print(np.argmin(a))
    print(np.argmax(a))
[[1 2 3]
 [4 5 6]]
0
5    

* np.where()

ifelse의 쓰임과 동일, 각 요소에 해당 조건에 대한 참, 거짓 여부 판단
참인 요소의 인덱스 값을 출력한다
새로운 칼럼을 만들 때 많이 사용한다

>>> a = np.array([6,7,8,9,10])
	a
    
>>> a > 7
array([False, False,  True,  True,  True])

>>> np.where(a>7)    #'a>7'의 조건에 참인 값의 인덱스를 출력
(array([2, 3, 4], dtype=int64),)

>>> a[np.where(a>7)]    #인덱스 번호를 검색
array([ 8,  9, 10])

>>> np.where(a>7, "pass", "fail")   #조건이 참일 때와 거짓일 때 실행할 문장도 줄 수 있다
array(['fail', 'fail', 'pass', 'pass', 'pass'], dtype='<U4')
>>> a = np.arange(-15, 15).reshape(5,6) ** 2
	a
array([[225, 196, 169, 144, 121, 100],
       [ 81,  64,  49,  36,  25,  16],
       [  9,   4,   1,   0,   1,   4],
       [  9,  16,  25,  36,  49,  64],
       [ 81, 100, 121, 144, 169, 196]])    

#각 행별로 최댓값은?
>>> np.max(a, axis=1)
array([225,  81,   9,  64, 196])

#각 열별로 평균은?
>>> np.mean(a, axis=0)
array([81., 76., 73., 72., 73., 76.])

>>> a[np.where(a<10)]
array([9, 4, 1, 0, 1, 4, 9])

#10보다 작은 것은 모두 0으로, 크거나 같은 것은 1로 바꾸자
>>> np.where(a<10, 0, 1)
array([[1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1],
       [0, 0, 0, 0, 0, 0],
       [0, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1]])

* python과 numpy의 실행 속도 차이 이유

① 메모리의 저장 위치
파이썬은 다소 복잡하게 데이터가 저장되고, 이에 비해 넘파이는 간단한 경로로 저장된다

② 넘파이는 데이타를 새로 만들지 않는다 실행(변경 ..)만 할 뿐이다 -> 새로운 데이터가 저장될 일이 많이 없다

③ 넘파이는 C언어를 사용한다 -> C언어는 어떤 interpreter 언어보다도 가장 처리속도가 빠르다

0개의 댓글