Numpy 기초

불리언 인덱싱(booleam indexing)

numpy 불리언 인덱싱은 배열 각 요소의 선택 여부를 Ture, False 로 지정하는 방식입니다.
해당 인덱스의 True만을 조회합니다.

import numpy as np
import matplotlib.pyplot as plt
def pprint(arr):
    print('type : {}'.format(type(arr)))
    print('shape : {}, demention : {}, dtype : {}'.format(arr.shape, arr.ndim, arr.dtype))
    print("array's Data : \n", arr)

a1배열에서 요소의 값이 짝수인 요소들의 총합 구하기

a1 = np.arange(1, 25).reshape((4, 6))
pprint(a1)
type : <class 'numpy.ndarray'>
shape : (4, 6), demention : 2, dtype : int64
array's Data : 
 [[ 1  2  3  4  5  6]
 [ 7  8  9 10 11 12]
 [13 14 15 16 17 18]
 [19 20 21 22 23 24]]
even_arr = a1%2==0
pprint(even_arr)
type : <class 'numpy.ndarray'>
shape : (4, 6), demention : 2, dtype : bool
array's Data : 
 [[False  True False  True False  True]
 [False  True False  True False  True]
 [False  True False  True False  True]
 [False  True False  True False  True]]
# a1[a1%2==0] 과 동일한 의미이다.
a1[even_arr]
array([ 2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24])

Boolean Indexing 의 응용

  • 2014년 시애틀 강수량 데이터 사용
  • 1년중 1월의 평균 강수량 구하기
import pandas as pd
# 데이터 로딩
rains_in_seattle = pd.read_csv('./seattle2014.csv')
rains_arr = rains_in_seattle['PRCP'].values
print('Data Sizd:', len(rains_arr))
Data Sizd: 365
# 날짜 배열
days_arr = np.arange(0, 365)
# 1월인 날을 구하기 위해 boolean indexing
condition_jan = days_arr < 31
# 40일까지 조회
condition_jan[:40]
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True, False, False, False, False, False,
       False, False, False, False])
# 1월의 강수량 추출 (40일)
rains_jan = rains_arr[condition_jan]
# 1월의 강수량 데이터 수
len(rains_jan)
31
# 1월 강수량 총합
np.sum(rains_jan)
940
# 1월 평균 강수량
np.mean(rains_jan)
30.322580645161292

원하는 달을 input으로 받아 강수량을 알려주는 프로그램 작성

days_arr = np.arange(0, 361)

month = int(input('해당 월을 숫자로 입력하시오'))

start = (month-1)*30
end = month * 30
rains_month = days_arr[start:end]

print('데이터 수 : ', len(rains_month))
print('총 강수량 : ', np.sum(rains_month))
print('평균 강수량 : ', np.mean(rains_month))
해당 월을 숫자로 입력하시오7
데이터 수 :  30
총 강수량 :  5835
평균 강수량 :  194.5

팬시 인덱싱(Fancy indexing)

배열에 인덱스 배열을 전달하여 요소를 참조하는 방법이다.

arr = np.arange(1, 25).reshape((4, 6))
pprint(arr)
type : <class 'numpy.ndarray'>
shape : (4, 6), demention : 2, dtype : int64
array's Data : 
 [[ 1  2  3  4  5  6]
 [ 7  8  9 10 11 12]
 [13 14 15 16 17 18]
 [19 20 21 22 23 24]]

fancy case 1

[arr[0,0], arr[1,2], arr[2,2], arr[3,3]]
[1, 9, 15, 22]
# (0,0), (1,1), (2,2), (3,3) 으로 배열 전달
arr[[0, 1, 2, 3], [0, 1, 2, 3]]
array([ 1,  8, 15, 22])

fancy case 2

# 전체 행에 대해 1,2 번 칼럼 참조
arr[:, [1, 2]]
array([[ 2,  3],
       [ 8,  9],
       [14, 15],
       [20, 21]])

배열 변환

배열을 변환하는 방법으로 전치, shape변환, 요소추가, 결합, 분리 등이 있다.

[numpy.ndarray 객체] . T

전치(Tranpose)는 행렬의 인덱스가 바뀌는 변환이다. (a, b) -> (b, a)로 변환된다.

a = np.random.randint(1, 10, (2, 3))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (2, 3), demention : 2, dtype : int64
array's Data : 
 [[4 1 5]
 [4 2 5]]
pprint(a.T)
type : <class 'numpy.ndarray'>
shape : (3, 2), demention : 2, dtype : int64
array's Data : 
 [[4 4]
 [1 2]
 [5 5]]

배열 형태 변경

[numpy.ndarray 객체] . ravel( )

  • ravel 은 배열의 shape을 1차원 배열로 만든다.
a = np.random.randint(1, 10, (2, 3))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (2, 3), demention : 2, dtype : int64
array's Data : 
 [[9 3 6]
 [3 5 6]]
a.ravel()
array([9, 3, 6, 3, 5, 6])
b = a.ravel()
pprint(b)
type : <class 'numpy.ndarray'>
shape : (6,), demention : 1, dtype : int64
array's Data : 
 [9 3 6 3 5 6]
b[0]=99
pprint(b)
type : <class 'numpy.ndarray'>
shape : (6,), demention : 1, dtype : int64
array's Data : 
 [99  3  6  3  5  6]
  • 반환 행렬의 데이터를 변경하면 원래의 a 행렬도 변경된다.
pprint(a)
type : <class 'numpy.ndarray'>
shape : (2, 3), demention : 2, dtype : int64
array's Data : 
 [[99  3  6]
 [ 3  5  6]]

[numpy.ndarray 객체] . reshape( )

  • reshape은 데이터 변경 없이 지정된 shape으로 변환한다.
a = np.random.randint(1, 10, (2, 3))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (2, 3), demention : 2, dtype : int64
array's Data : 
 [[2 2 1]
 [8 7 7]]
result = a.reshape((3, 2, 1))
pprint(result)
type : <class 'numpy.ndarray'>
shape : (3, 2, 1), demention : 3, dtype : int64
array's Data : 
 [[[2]
  [2]]

 [[1]
  [8]]

 [[7]
  [7]]]

배열 요소 추가 삭제

resize( )

  • np.resize(a, new_shape)
  • np.ndarry.resize(new_shape, refcheck=True)
  • 배열의 shape과 크기를 변경합니다.
a = np.random.randint(1, 10, (2, 6))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (2, 6), demention : 2, dtype : int64
array's Data : 
 [[6 6 3 6 4 5]
 [2 8 9 6 6 8]]
a.resize((6, 2))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (6, 2), demention : 2, dtype : int64
array's Data : 
 [[6 6]
 [3 6]
 [4 5]
 [2 8]
 [9 6]
 [6 8]]
  • 배열의 요소 수를 늘이거나 줄일 수 있다.
a = np.random.randint(1, 10, (2, 6))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (2, 6), demention : 2, dtype : int64
array's Data : 
 [[4 4 1 6 6 5]
 [8 6 3 8 1 5]]
a.resize((2, 10))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (2, 10), demention : 2, dtype : int64
array's Data : 
 [[4 4 1 6 6 5 8 6 3 8]
 [1 5 0 0 0 0 0 0 0 0]]
a = np.random.randint(1, 10, (2, 6))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (2, 6), demention : 2, dtype : int64
array's Data : 
 [[1 6 7 3 7 5]
 [5 8 1 5 1 8]]
a.resize((3, 3))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (3, 3), demention : 2, dtype : int64
array's Data : 
 [[1 6 7]
 [3 7 5]
 [5 8 1]]

append( )

  • np.append(arr, values, axis=None)
  • 배열의 끝에 값을 추가
a = np.arange(1, 10).reshape(3, 3)
pprint(a)
b = np.arange(10, 19).reshape(3, 3)
pprint(b)
type : <class 'numpy.ndarray'>
shape : (3, 3), demention : 2, dtype : int64
array's Data : 
 [[1 2 3]
 [4 5 6]
 [7 8 9]]
type : <class 'numpy.ndarray'>
shape : (3, 3), demention : 2, dtype : int64
array's Data : 
 [[10 11 12]
 [13 14 15]
 [16 17 18]]
  • axis을 자정하지 않으면 1차원 배열로 변형되어 결함된다.
result = np.append(a, b)
pprint(result)
type : <class 'numpy.ndarray'>
shape : (18,), demention : 1, dtype : int64
array's Data : 
 [ 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18]
pprint(a)
type : <class 'numpy.ndarray'>
shape : (3, 3), demention : 2, dtype : int64
array's Data : 
 [[1 2 3]
 [4 5 6]
 [7 8 9]]
  • axis=0 설정시 나머지 shape은 같아야한다. (이외는 오류 발생)
result = np.append(a, b, axis=0)
pprint(result)
type : <class 'numpy.ndarray'>
shape : (6, 3), demention : 2, dtype : int64
array's Data : 
 [[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]
 [13 14 15]
 [16 17 18]]
different_shape_arr = np.arange(10, 20).reshape(2, 5)
pprint(different_shape_arr)
type : <class 'numpy.ndarray'>
shape : (2, 5), demention : 2, dtype : int64
array's Data : 
 [[10 11 12 13 14]
 [15 16 17 18 19]]
  • 오류 발생 예제
np.append(a, different_shape_arr, axis=0)
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

<ipython-input-57-5f18e0ed6945> in <module>
----> 1 np.append(a, different_shape_arr, axis=0)


<__array_function__ internals> in append(*args, **kwargs)


~/opt/anaconda3/lib/python3.8/site-packages/numpy/lib/function_base.py in append(arr, values, axis)
   4743         values = ravel(values)
   4744         axis = arr.ndim-1
-> 4745     return concatenate((arr, values), axis=axis)
   4746 
   4747 


<__array_function__ internals> in concatenate(*args, **kwargs)


ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 3 and the array at index 1 has size 5
  • axis = 1 설정 시, shape[1]을 제외한 나머지 shape은 같아야한다.
# axis = 1
result = np.append(a, b, axis=1)
pprint(result)
type : <class 'numpy.ndarray'>
shape : (3, 6), demention : 2, dtype : int64
array's Data : 
 [[ 1  2  3 10 11 12]
 [ 4  5  6 13 14 15]
 [ 7  8  9 16 17 18]]

insert( )

  • np.insert(arr, obj, values, axis=None)
  • axis를 지정하지 않으며 1차원 배열로 변환
  • 추가할 방향을 axis 로 지정
a = np.arange(1, 10).reshape(3, 3)
pprint(a)
type : <class 'numpy.ndarray'>
shape : (3, 3), demention : 2, dtype : int64
array's Data : 
 [[1 2 3]
 [4 5 6]
 [7 8 9]]
# a 배열을 1차원 배열로 변환하고 1번index에 999 추가
np.insert(a, 1, 999)
array([  1, 999,   2,   3,   4,   5,   6,   7,   8,   9])
# a 배열의 axis 0방향 1번 인덱스에 추가
# index가 1인 row에 999 추가
np.insert(a, 1, 999, axis=0)
array([[  1,   2,   3],
       [999, 999, 999],
       [  4,   5,   6],
       [  7,   8,   9]])
# a 배열의 axis 1 방향 1번 인덱스에 추가
# index가 1인 column에 999 추가
np.insert(a, 1, 999, axis=1)
array([[  1, 999,   2,   3],
       [  4, 999,   5,   6],
       [  7, 999,   8,   9]])

delete( )

  • np.delete(arr, obj, axis=None)
  • axis를 지정하지 않으며 1차원 배열로 변환
  • 삭제할 방향을 axis 로 지정
  • delete 함수는 원본 배열을 변경하지 않으며 새로운 배열을 반환
a = np.arange(1, 10).reshape(3, 3)
pprint(a)
type : <class 'numpy.ndarray'>
shape : (3, 3), demention : 2, dtype : int64
array's Data : 
 [[1 2 3]
 [4 5 6]
 [7 8 9]]
# a 배열을 1차원 배열로 변환하고 1번 index 삭제
np.delete(a, 1)
array([1, 3, 4, 5, 6, 7, 8, 9])
# a 배열의 axis 0 방향 1번 index 행을 삭제한 배열 생성하여 반환
np.delete(a, 1, axis=0)
array([[1, 2, 3],
       [7, 8, 9]])
# a 배열의 axis 1방향 1번 index 인 열을 삭제한 배열을 생성하여 반환
np.delete(a, 1, axis=1)
array([[1, 3],
       [4, 6],
       [7, 9]])

배열 결합

배열과 배열을 결합하는 함수로 np.concatenate, np.vstack, np.hstack 가 있다.

np.concatenate

  • concatenate((a1, a2, …), axis=0)
a = np.arange(1, 7).reshape((2, 3))
pprint(a)
b = np.arange(7, 13).reshape((2, 3))
pprint(b)
type : <class 'numpy.ndarray'>
shape : (2, 3), demention : 2, dtype : int64
array's Data : 
 [[1 2 3]
 [4 5 6]]
type : <class 'numpy.ndarray'>
shape : (2, 3), demention : 2, dtype : int64
array's Data : 
 [[ 7  8  9]
 [10 11 12]]
# axis=0 방향으로 두 배열 결합, axis 기본값 = 0
result = np.concatenate((a, b))
result
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])
# axis =1 방향으로 두 배열 결합
result = np.concatenate((a, b), axis=1)
result
array([[ 1,  2,  3,  7,  8,  9],
       [ 4,  5,  6, 10, 11, 12]])

np.vstack 수직 방향 배열 결합

  • np.vstack(tuple)
  • 튜플로 설정된 여러 배열을 수직방향으로 연결
  • np.concatenate(tup, axis=0)와 동일하다.
a = np.arange(1, 7).reshape((2, 3))
pprint(a)
b = np.arange(7, 13).reshape((2, 3))
pprint(b)
type : <class 'numpy.ndarray'>
shape : (2, 3), demention : 2, dtype : int64
array's Data : 
 [[1 2 3]
 [4 5 6]]
type : <class 'numpy.ndarray'>
shape : (2, 3), demention : 2, dtype : int64
array's Data : 
 [[ 7  8  9]
 [10 11 12]]
np.vstack((a, b))
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])
np.vstack((a, b, a, b))
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12],
       [ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

np.vhstack 수평방향 배열 결합

  • np.hstack(tuple)
  • 튜플로 설정된 여러 배열을 수평방향으로 연결(axis=1 방향)
a = np.arange(1, 7).reshape((2, 3))
pprint(a)
b = np.arange(7, 13).reshape((2, 3))
pprint(b)
type : <class 'numpy.ndarray'>
shape : (2, 3), demention : 2, dtype : int64
array's Data : 
 [[1 2 3]
 [4 5 6]]
type : <class 'numpy.ndarray'>
shape : (2, 3), demention : 2, dtype : int64
array's Data : 
 [[ 7  8  9]
 [10 11 12]]
np.hstack((a, b))
array([[ 1,  2,  3,  7,  8,  9],
       [ 4,  5,  6, 10, 11, 12]])
np.hstack((a, b, a, b, ))
array([[ 1,  2,  3,  7,  8,  9,  1,  2,  3,  7,  8,  9],
       [ 4,  5,  6, 10, 11, 12,  4,  5,  6, 10, 11, 12]])

배열 분리

  • np.hsplit( ) : 지정한 배열을 수평 방향으로 분할
  • np.vsplit( ) : 지정한 배열을 수직 방향으로 분할

np.hsplit(ary, indices_or_sections)

a = np.arange(1, 25).reshape((4, 6))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (4, 6), demention : 2, dtype : int64
array's Data : 
 [[ 1  2  3  4  5  6]
 [ 7  8  9 10 11 12]
 [13 14 15 16 17 18]
 [19 20 21 22 23 24]]
result = np.hsplit(a, 2)
result
[array([[ 1,  2,  3],
        [ 7,  8,  9],
        [13, 14, 15],
        [19, 20, 21]]),
 array([[ 4,  5,  6],
        [10, 11, 12],
        [16, 17, 18],
        [22, 23, 24]])]
result = np.hsplit(a, 3)
result
[array([[ 1,  2],
        [ 7,  8],
        [13, 14],
        [19, 20]]),
 array([[ 3,  4],
        [ 9, 10],
        [15, 16],
        [21, 22]]),
 array([[ 5,  6],
        [11, 12],
        [17, 18],
        [23, 24]])]
np.hsplit(a, [1, 3, 5])
[array([[ 1],
        [ 7],
        [13],
        [19]]),
 array([[ 2,  3],
        [ 8,  9],
        [14, 15],
        [20, 21]]),
 array([[ 4,  5],
        [10, 11],
        [16, 17],
        [22, 23]]),
 array([[ 6],
        [12],
        [18],
        [24]])]

np.vsplit(ary, indices_or_sections)

a = np.arange(1, 25).reshape((4, 6))
pprint(a)
type : <class 'numpy.ndarray'>
shape : (4, 6), demention : 2, dtype : int64
array's Data : 
 [[ 1  2  3  4  5  6]
 [ 7  8  9 10 11 12]
 [13 14 15 16 17 18]
 [19 20 21 22 23 24]]
result=np.vsplit(a, 2)
result
[array([[ 1,  2,  3,  4,  5,  6],
        [ 7,  8,  9, 10, 11, 12]]),
 array([[13, 14, 15, 16, 17, 18],
        [19, 20, 21, 22, 23, 24]])]
np.array(result).shape
(2, 2, 6)
result=np.vsplit(a, 4)
result
[array([[1, 2, 3, 4, 5, 6]]),
 array([[ 7,  8,  9, 10, 11, 12]]),
 array([[13, 14, 15, 16, 17, 18]]),
 array([[19, 20, 21, 22, 23, 24]])]
np.array(result).shape
(4, 1, 6)
# row를 1, 2-3, 4번째 라인으로 구분
np.vsplit(a, [1, 3])
[array([[1, 2, 3, 4, 5, 6]]),
 array([[ 7,  8,  9, 10, 11, 12],
        [13, 14, 15, 16, 17, 18]]),
 array([[19, 20, 21, 22, 23, 24]])]