본문 바로가기

Python/Data Analysis Library

Part03 Chapter.02 데이터 분석 라이브러리-03. Numpy method (실습)

Numpy

1. Numpy Array and Operation

  • numpy의 기본적인 사용법에 대해서 배워봅니다.
  • numpy에서 numpy.array를 만드는 여러가지 방법과 지원하는 연산자에 대해서 공부합니다.

1.1. Numpy Array creation

# numpy 라이브러리를 불러옵니다.

import numpy as np

 

# 파이썬 리스트 선언
data = [1, 2, 3, 4, 5]

 

 
# 파이썬 2차원 리스트(행렬) 선언
data2 = [[1,2],[3,4]]

 

 
# 파이썬 list를 numpy array로 변환합니다.

# numpy array를 만드는 방식의 대부분은 파이썬 리스트를 np.array로 변환하는 방식입니다.

arr = np.array(data)

arr
>>> array([1, 2, 3, 4, 5])

 

# 2차원 리스트를 np.array로 만듭니다.

# 2차원 리스트를 np.array로 만듭니다.
arr2 = np.array(data2) # data2라는 리스트를 numpy array로 만들어라.
arr2 # 2차원 numpy array -> 행렬!

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

 

# 0부터 9까지 숫자를 자동으로 생성한 array
np.array(list(range(10)))
np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

 

# 10부터 99까지 숫자를 자동으로 생성한 array

np.arange(10,100)
더보기
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
       27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
       44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
       61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
       78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
       95, 96, 97, 98, 99])
arr.shape (5, ) != (5,1)
arr2.shape (2 , 2)
>>> (2, 2)

 


 

1.2. Reshaping array

# 3 x 3 행렬을 만들어봅시다

x = np.array([[1,2,3],
             [4,5,6],
             [7,8,9]])
x
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

 

# reshape을 이용하여 만들어봅시다.
np.arange(1,10).reshape(3, 3) # (9, )-> (3, 3)
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5]])

 

# 펼치기

x.reshape(-1, ) 

(-1,) (9, ) numpy에 reshape 함수에 -1를 넣으면 -1은 나머지의 세트와 합쳐서 자동계산
(3, 3)

 


 

1.3. Concatenation of arrays

 

arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])

arr1 + arr2 = ? -> 벡터연산이 됨/ 리스트타입과는 다름
arr1 + arr2 
>>> array([5, 7, 9])

arr1와 arr2를 합칩니다
np.concatenate([arr1, arr2]) 
>>> array([1, 2, 3, 4, 5, 6])

 

# stacking vertically

np.vstack([arr1, arr2])
array([[1, 2, 3],
       [4, 5, 6]])

 

 

# stacking horizontally

np.hstack([arr1, arr2])
array([1, 2, 3, 4, 5, 6])

 


 

1.4. Array Arithmetic (like vector) --> Universal Function

# v1 = (1, 2, 3), v2 = (4, 5, 6) 벡터 2개 생성하기.

v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])

 

# 리스트로 더하기 연산해보기
L1 = [1, 2, 3]
L2 = [4, 5, 6]
L1 + L2
[1, 2, 3, 4, 5, 6]
 
#  vector addition 백터연산
v1 + v2
array([5, 7, 9])

 

#  vector subtraction 백터연산

v1 - v2
array([-3, -3, -3])

 

# (not vector operation) elementwise multiplication
v1 * v2
array([ 4, 10, 18])

 

# dot product
v1 @ v2 # 1x4 + 2X5 + 3X6
32

1.5. Broadcast and Universal Function

  • 서로 크기가 다른 numpy array를 연산할 때, 자동으로 연산을 전파(broadcast)해주는 기능.
  • 행렬곱 연산을 할 때 편리하다.
arr1 = np.array([1, 2, 3])
arr2 = np.array([[-1,-1,-1],[1, 1, 1,]])

arr2.shape
(2, 3)

 

 

# 2개의 array를 더해보면?
arr1 + arr2 # 2->2->3(v)
array([[0, 1, 2],
       [2, 3, 4]])

 

# 2개의 array를 곱해보면? (**)
arr1 * arr2
array([[-1, -2, -3],
       [ 1,  2,  3]])

 

  • Universal Function : broadcast 기능을 확장해서, numpy array의 모든 원소에 동일한 함수를 반복문으로 적용한 것과 같은 효과를 내는 기능.
# f = lambda x : 1/x
f = lambda x : 1/x
arr1= np.array([1., 2., 3.])
for i in range(arr1.shape[0]):
    arr1[i] = f(arr1[i])
print(arr1)


arr1= np.array([1., 2., 3.])
print(1 / arr1) # Universal Function
[1.         0.5        0.33333333]
[1.         0.5        0.33333333]

 

# f = lambda x : x + 2
arr1 = arr1 * 3
arr1
array([15., 18., 21.])

 


1.6. Indexing

  • numpy array의 indexing은 python list의 indexing과 같다!
arr1 = np.arange(10)
arr1

>>> array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
 
# 첫번째 원소
arr1[0]
>>> 0
 
# 마지막 원소
arr1[-1]
>>> 9
 
# 앞에서부터 원소 3개 slicing
arr1[:3]
>>> array([0, 1, 2])

arr2 = np.array([[1, 2, 3, 4],
               [5, 6, 7, 8],
               [9, 10, 11, 12]])
arr2
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])

 

# arr2의 2row, 3column 원소 = 7
arr2[1][2]
arr2[1, 2] # numpy array indexing에서 추가된것!
>>> 7

 

# arr2의 세번째 column [3, 7, 11]
arr2[0, 2]
arr2[1, 2]
arr2[2, 2]
arr2[ : , 2]
array([ 3,  7, 11])

 

# arr2의 두번째 row
# arr2의 두번째 row
arr2[ 1, : ]
array([5, 6, 7, 8])

2. Numpy Methods

  • numpy에서 사용되는 여러가지 함수들을 사용해봅시다.

2.1. Math Functions

# 표준정규분포에서 random sampling을 한 원소를 가지는 5x3 행렬을 만든다.
mat1 = np.random.randn(5, 3)
mat1
array([[ 2.45760313,  0.51453728, -0.60537909],
       [ 1.66107988,  1.13174898,  0.45791088],
       [ 0.59030187,  0.15268791, -0.70872446],
       [ 0.21876355,  1.07496683, -1.5666292 ],
       [-0.38959035, -0.35822517,  1.36738604]])

 

# mat1에 절대값 씌우기
np.abs(mat1)
array([[2.45760313, 0.51453728, 0.60537909],
       [1.66107988, 1.13174898, 0.45791088],
       [0.59030187, 0.15268791, 0.70872446],
       [0.21876355, 1.07496683, 1.5666292 ],
       [0.38959035, 0.35822517, 1.36738604]])

 

# mat1 제곱하기

np.square(mat1)
array([[6.03981315, 0.26474862, 0.36648384],
       [2.75918638, 1.28085576, 0.20968238],
       [0.3484563 , 0.0233136 , 0.50229035],
       [0.04785749, 1.15555368, 2.45432706],
       [0.15178064, 0.12832527, 1.86974458]])

 

# mat1의 제곱근 구하기

np.sqrt(mat1)      nan = not a number 루트안에 마이너스는 허수가 나와서 실수로 표현안됨
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:2: RuntimeWarning: invalid value encountered in sqrt
  
array([[1.56767443, 0.71731254,        nan],
       [1.28882888, 1.06383692, 0.67669113],
       [0.76831105, 0.390753  ,        nan],
       [0.46772165, 1.03680607,        nan],
       [       nan,        nan, 1.16935283]])

 

# linear algebra functions

# C++ 프로그래밍 언어에서 벡터(std::vector)는 유동적으로 크기 조절이 가능한 배열 자료 구조를 구현한 것이다

# 파이썬에서 벡터는 한 개 또는 그이상의 "스칼라" 값으로 구성된 튜플이다.

vec = np.array([1, 2, 2])
 
# 1. norm (백터의 크기)
np.linalg.norm(vec)  ---> vector L2 norm

 

# 2. eigenvalue(선형대수의 고유값)
mat = np.array([[1,2],
               [3,4]])
np.linalg.eig(mat)

(array([-0.37228132,  5.37228132]), array([[-0.82456484, -0.41597356],
        [ 0.56576746, -0.90937671]]))

 


 

2.2. Aggregation functions

#rand는 0~1 사이에 아무거나 찍어준다

mat2 = np.random.rand(3, 2) #rand는 0~1 사이에 아무거나 찍어준다
mat2
array([[0.33702761, 0.8267591 ],
       [0.37960553, 0.90505923],
       [0.42097973, 0.38001594]])

 

# Summation
# Summation
np.sum(mat2)        # 전체
np.sum(mat2,axis=0) # column 대로 더했음
np.sum(mat2,axis=1) # row 대로 더함
array([1.13761286, 2.11183427])

 

# mean 
np.mean(mat2) # 전체평균
np.mean(mat2,axis=0) # column 대로 평균
np.mean(mat2,axis=1) # raw 대로 평균
array([0.58189335, 0.64233238, 0.40049783])

 

# std / Numpy.std() 함수는 지정된 축을 따라 주어진 배열의 표준 편차를 계산합니다.

np.std(mat2)
0.23172147686805705

 

# min, max

np.min(mat2, axis = 0) # column
np.max(mat2, axis = 1) # raw
array([0.8267591 , 0.90505923, 0.42097973])

 

# 최소값이 있는 Index
np.argmin(mat2, axis=0 )
array([0, 2])

 

# 최대값이 있는 Index

np.argmax(mat2, axis=1 )
array([1, 1, 0])

 

# 그냥 정렬 (오름차순 정렬만 지원합니다)

np.sort(mat2)
array([[0.33702761, 0.8267591 ],
       [0.37960553, 0.90505923],
       [0.38001594, 0.42097973]])

 

np.sort(mat2,axis=0) # column 행
array([[0.33702761, 0.38001594],
       [0.37960553, 0.8267591 ],
       [0.42097973, 0.90505923]])

 

# 만약에 내림차순을 하겠다?
np.sort(mat2,axis=0)[::-1]
array([[0.42097973, 0.90505923],
       [0.37960553, 0.8267591 ],
       [0.33702761, 0.38001594]])​

 

 

# index를 정렬 /원래 어디에 있어는지 사용
np.argsort(mat2 ,axis = 0)
array([[0, 2],
       [1, 0],
       [2, 1]])

3. Performance Check

  • Universal Function 기능을 통해 반복문을 사용한 것보다 훨씬 빠른 성능을 냅니다.
  • 직접 실험을 통해 그 차이를 확인해보겠습니다.
def reverse_num(values):
    output = np.empty(len(values))
    
    for i in range(len(values)):
        output[i] = 1.0 / values[i]
    
    return output

 

# 1부터 100까지 범위에서 100000000개를 랜덤으로 뽑아서 array를 만듭니다.

big_array = np.random.randint(1,100, 100000000)
big_array
array([90, 91, 70, ..., 99,  3, 27])

 

%timeit reverse_num(big_array)
1 loop, best of 5: 2.19 s per loop

 

# numpy의 universal function이 훨씬 빠르다! 단, 크기가 클떄 좋음.
%timeit 1.0 / big_array
100 loops, best of 5: 1.99 ms per loop