파이썬 기초: 라이브러리-Numpy

본 페이지에서는 코드의 실행결과를 제공하지 않습니다. 직접 타이핑하고 실행해 보세요.

1. Numpy 개요

1-1. Numpy란?

  • NumPy : Numerical Python
  • 고성능의 과학계산 컴퓨팅과 데이터 분석에 필요한 기본패키지
  • 행렬이나 대규모의 다차원 배열을 쉽게 처리
  • 계산과학(Computational Science) 분야의 복잡한 연산을 지원
  • SciPy, Matplotlib, Pandas 등에 채용되어 더 복잡한 연산을 쉽게 처리 가능하도록 지원

1-2. NumPy에서 제공하는 기능

  • ndarray 지원: 빠르고 메모리를 효율적으로 사용하며, 벡터 산술연산과 세련된 브로드캐스팅 기능을 제공하는 다차원 배열
  • 반복문을 작성할 필요 없이 전체 데이터 배열에 대해 빠른 연산을 제공하는 표준 수학 함수
  • 배열 데이터를 디스크에 쓰거나 읽을 수 있는 도구와 메모리에 올려진 파일을 사용하는 도구
  • 선형대수, 난수 발생기, 푸리에 변환 기능
  • C, C++, 포트란으로 쓰여진 코드를 통합하는 도구
    • 사용하기 편한 C API제공
    • 데이터를 다른 저수준 언어로 쓰여진 외부 라이브러리에 쉽게 전달할 수 있도록 지원
    • 외부 라이브러리에서 반환된 데이터를 파이썬의 NumPy 배열 형태로 불러올 수 있도록 지원
    • 파이썬을 레거시 C/C++/포트란 기반의 코드를 래핑하여 동적이며 쉽게 사용할 수 있는 인터페이스를 만들 수 있는 언어로 만들어 줌

1-3. Numpy를 잘 활용하려면

  • NumPy는 자체적으로는 고수준의 데이터 분석 기능을 제공하지 않으므로
  • 먼저 NumPy 배열과 배열기반의 컴퓨팅에 대한 이해가 선행된다면
  • 더 상위 레벨에서 데이터 분석과 같은 기능을 제공하는 Pandas 등의 도구들을 더욱 효율적으로 사용할 수 있음

1-4. 대부분의 데이터 분석 애플리케이션에서 중요하게 사용되는 기능

  • 벡터배열 상에서 데이터 개조, 정제, 부분집합, 필터링, 변형, 이종연산의 빠른 수행
  • 정렬, 유일 원소 찾기, 집합연산과 같은 일반적인 배열 처리 알고리즘
  • 통계의 효과적인 표현과 데이터의 수집/요약
  • 이종의 데이터 묶음을 병합하고 엮기 위한 데이터 정렬과 데이터 간의 관계 조작
  • if ~ elif ~ else 포함 반복문 대신 사용가능한 조건절 표현을 할 수 있는 배열 표현
  • 데이터 그룹 전체에 적용할 수 있는 수집, 변형, 함수의 적용과 같은 데이터 처리

2. Numpy 실습 예제

2-1. ndarray (n-Dimension Array)

  • numpy import

      import numpy as np
    
  • ndarray 배열은 산술 연산이 가능함
  • ndarray 배열은 각 차원의 크기를 알려주는 shape라는 튜플을 가짐
  • ndarray 배열은 배열에 저장된 자료형을 알려주는 dtype이라는 객체를 가짐

      data = np.random.randn(2, 3)
      print(data)
    
      data
    
      print(data * 10)
      print(data + data)
    
      print(data.shape)
      print(data.dtype)
    
  • ndarray의 생성과 사용

      data1 = [6, 7.5, 8, 0, 1]
      arr1 = np.array(data1)
      arr1
    
      print(arr1.ndim)
      print(data1)
    
  • 같은 길이의 리스트가 담겨있는 순차 데이터는 다차원 배열로 변환이 가능함

      data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
      arr2 = np.array(data2)
      arr2
    
      print(arr2.ndim)
      print(arr2.shape)
    
  • 명시적으로 지정하지 않는 한 np.array는 생성될 때 적절한 자료형을 지정하여 적용함

      print(arr1.dtype)
      print(arr2.dtype)
    
  • 새로운 배열을 생성하기 위한 다양한 함수 보유

      np.zeros(10)        # 10개의 요소가 0으로 채워진 1차원 배열 생성
    
      np.zeros((3, 6))    # 6개의 요소를 가진 1차원 배열이 3개가 포함된 2차원 배열 생성
    
      np.empty((2, 3, 2)) # empty 함수는 초기화되지 않은 배열 생성. 원하는 형태를 정의한 튜플을 넘기면 해당 형태로 생성
    
  • 파이썬의 range 함수의 배열 버전인 arange 함수

      np.arange(15)
    
      range(15)
    
  • 데이터 타입 확인

      arr0 = np.array([1., 2, 3])
      arr1 = np.array([1, 2, 3], dtype=np.float64)
      arr2 = np.array([1, 2, 3], dtype=np.int32)
    
      print(arr0.dtype)
      print(arr0)
      print(arr1.dtype)
      print(arr1)
      print(arr2.dtype)
      print(arr2)
    
      arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
      arr1 = arr.astype(np.int32)
      print(arr1)
    
      import copy
    
      arr2 = arr1
      arr2[0] = 10
      print(arr2)
      print(arr1)
    
      arr3 = copy.copy(arr1)
      arr3[0] = 20
      print(arr3)
      print(arr1)
    
      numeric_strings = np.array(['1.25', '-9.6', '42'], dtype=np.string_)
      print(numeric_strings)
      numeric_strings.astype(float)
    
      int_array = np.arange(10)
      print(int_array.dtype)
      calibers = np.array([.22, .270, .357, .380, .44, .50], dtype=np.float64)
      print(calibers.dtype)
      int_array.astype(calibers.dtype)
    
      empty_uint32 = np.empty(8, dtype='u4')
      empty_uint32
    
  • 산술 연산

      arr = np.array([[1., 2., 3.], [4., 5., 6.]])
      arr
    
      print(arr + arr)
      print(arr - arr)
      print(arr * arr)
      print(1 / arr)
      print(arr ** 0.5)
    
      arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])
      arr2
    
      arr2 > arr
    

2-2. 인덱싱과 슬라이싱

  • 기본 인덱싱

      arr = np.arange(10)
      arr
    
      arr[5]
    
      arr[5:8]
    
      arr[5:8] = 12
    
      arr
    
      arr_slice = arr[5:8]
      arr_slice
    
      arr_slice[1] = 12345
      arr
    
      arr_slice[:] = 64
      arr
    
      arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
      arr2d[2]
    
      arr2d[0][2]
    
      arr2d[0, 2]
    
      arr3d = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
      arr3d
    
      arr3d[0]
    
      old_values = arr3d[0].copy()
      arr3d[0] = 42
      arr3d
    
      arr3d[0] = old_values
      arr3d
    
      arr3d[1, 0]
    
      x = arr3d[1]
      x
      x[0]
    
  • 슬라이스를 이용한 인덱싱

      arr
    
      arr[1:6]
    
      arr2d
    
      arr2d[:2]
    
      arr2d[:2, 1:]
    
      arr2d[1, :2]
    
      arr2d[:2, 2]
    
      arr2d[:, :1]
    
      arr2d[:2, 1:] = 0
      arr2d
    
  • 불린 인덱싱

      names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
      data = np.random.randn(7, 4)
    
      names
    
      data
    
      names == 'Bob'
    
      data[names == 'Bob']
    
      data[names == 'Bob', 2:]
    
      data[names == 'Bob', 3]
    
      names != 'Bob'
    
      data[(names != 'Bob')]
    
      data[~(names == 'Bob')]
    
      cond = names == 'Bob'
      data[~cond]
    
      mask = (names == 'Bob') | (names == 'Will')
      print(mask)
      data[mask]
    
      data[data < 0] = 0
      data
    
      data[names != 'Joe'] = 7
      data
    
  • 팬시 인덱싱

      arr = np.empty((8, 4))
      arr
    
      for i in range(8):
          arr[i] = i
      arr
    
      arr[[4, 3, 0, 6]]
    
      arr[[-3, -5, -7]]
    
      arr = np.arange(32)
      arr
    
      arr = arr.reshape((8, 4))
      arr
    
      arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]]
    

2-3. 전치행렬과 축 교환

arr = np.arange(15).reshape((3, 5))
arr
arr.T
arr = np.random.randn(6, 3)
arr
np.dot(arr.T, arr)
arr = np.arange(16).reshape((2, 2, 4))
arr
arr.transpose((1, 0, 2))
arr
arr.swapaxes(1, 2)

2-4. 유니버설 함수

  • ndarray 안에 있는 데이터 원소별로 연산을 수행하는 함수

      arr = np.arange(10)
      arr
    
      np.sqrt(arr)
    
      np.exp(arr)
    
      x = np.random.randn(8)
      y = np.random.randn(8)
      x
      y
      np.maximum(x, y)
    
      arr = np.random.randn(7) * 5
      print(arr)
    
      remainder, whole_part = np.modf(arr)
      print(remainder)
      print(whole_part)
    
      arr
      np.sqrt(arr)
      np.sqrt(arr, arr)
      arr
    

2-5. 배열을 사용한 데이터 처리

points = np.arange(-5, 5, 0.01) # 1000 equally spaced points
xs, ys = np.meshgrid(points, points)
ys
z = np.sqrt(xs  2 + ys  2)
z
import matplotlib.pyplot as plt

plt.imshow(z, cmap=plt.cm.gray); plt.colorbar()
plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values")
plt.draw()
plt.close('all')

2-5-1. 배열연산으로 조건절 표현하기

xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])

result = [(x if c else y)
          for x, y, c in zip(xarr, yarr, cond)]
result
result = np.where(cond, xarr, yarr)
result
arr = np.random.randn(4, 4)
arr
arr > 0
np.where(arr > 0, 2, -2)
np.where(arr > 0, 2, arr) # set only positive values to 2

2-5-2. 수학 메소드와 통계 메소드

arr = np.random.randn(5, 4)
arr
arr.mean()
np.mean(arr)
arr.sum()
arr.mean(axis=1)
arr.sum(axis=0)
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
arr.cumsum()
arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
arr
print(arr.cumsum(axis=0))
print(arr.cumprod(axis=1))

2-5-3. 불리언 배열을 위한 메소드

arr = np.random.randn(100)
(arr > 0).sum() # Number of positive values
arr
print(arr>0)
bools = np.array([False, False, True, False])
bools.any()
bools.all()

2-5-4. 정렬

arr = np.random.randn(6)
arr
arr.sort()
arr
arr = np.random.randn(5, 3)
arr
arr.sort(1)
arr
large_arr = np.random.randn(100)
print(large_arr)
large_arr.sort()
print(large_arr)
large_arr[int(0.5 * len(large_arr))]

2-5-5. 집합함수

names = np.array(['Joe', 'Will', 'Bob', 'Will', 'Bob', 'Joe', 'Joe'])
np.unique(names)
ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])
np.unique(ints)
# sorted(set(names))
set(names)
values = np.array([6, 0, 0, 3, 2, 5, 6])
np.in1d(values, [2, 3, 6])

2-5-6. 배열을 사용한 파일 입출력

arr = np.arange(10)
np.save('./some_array.txt', arr)
np.load('./some_array.txt.npy')
np.savez('./array_archive.npz', a=arr, b=arr)
arch = np.load('./array_archive.npz')
print(arch['b'])
print(arch['a'])
np.savez_compressed('./arrays_compressed.npz', a=arr, b=arr)
pwd
rm some_array.txt.npy
rm array_archive.npz
rm arrays_compressed.npz

2-6. 선형대수

x = np.array([[1., 2., 3.], [4., 5., 6.]])
y = np.array([[6., 23.], [-1, 7], [8, 9]])
x
y
x.dot(y)
np.dot(x, y)
np.ones(3)
np.dot(x, np.ones(3))
np.ones(3)
x @ np.ones(3)
from numpy.linalg import inv, qr
X = np.random.randn(5, 5)
mat = X.T.dot(X)
inv(mat)
mat.dot(inv(mat))
q, r = qr(mat)
r

2-7. 난수 생성

samples = np.random.normal(size=(4, 4))
samples
from random import normalvariate
N = 10000
%timeit samples = [normalvariate(0, 1) for _ in range(N)]
%timeit np.random.normal(size=N)
np.random.seed(1234)
rng = np.random.RandomState(1234)
rng.randn(10)