Numpy 다차원 배열 객체
data = np.arange(6).reshape(2,3)
%timeit np.arange(10000)
100000 loops, best of 3: 7.91 µs per loop
%timeit range(10000)
10000 loops, best of 3: 95.4 µs per loop
np.arange와 python 내장함수 range의 속도차이가..
data
array([[0, 1, 2], [3, 4, 5]])
스칼라 연산 배열의 각 원소마다 연산이 된다.
data * 10
array([[ 0, 10, 20], [30, 40, 50]])
data + 10
array([[10, 11, 12], [13, 14, 15]])
data / 2
array([[0, 0, 1], [1, 2, 2]])
data % 2
array([[0, 1, 0], [1, 0, 1]])
ndarray는 같은 자료형의 데이터만 담을 수 있다
data2 = list(['abd',1,2,3,'hello'])
data2
['abd', 1, 2, 3, 'hello']
data3 = np.array(['hello','hi',1,2,3])
data3
array(['hello', 'hi', '1', '2', '3'], dtype='|S5')
data3.dtype
dtype('S5')
위 결과에서 보이는것처럼 문자열과 정수가 섞였더니.. 모두 문자열로 변환이 되었네요..
data4 = np.array([5.,3.,4.,1,2,3])
data4
array([ 5., 3., 4., 1., 2., 3.])
data4.dtype
dtype('float64')
보시는 바와 같이 더 큰 자료형으로 변환이 일어난다는걸 알 수 있습니다.
자료형을 명시적으로 변환 할 수 있는 astype 메서드
arr = np.array([1,2,3,4,5,6])
arr.dtype
dtype('int64')
arr.astype(float)
array([ 1., 2., 3., 4., 5., 6.])
부동소수점으로 바뀌었습니다. string으로 바꿔봅시다.
arr2 = arr.astype(string_)
arr2
array(['1', '2', '3', '4', '5', '6'], dtype='|S21')
numeric_strings = np.array(['1.25','-9.6','42'], dtype=string_)
numeric_strings.astype(float)
array([ 1.25, -9.6 , 42. ])
배열과 스칼라 간의 연산 배열은 for문을 작성하지 않고 데이터를 일괄처리 가능 이를 벡터화라고 한다.
같은 크기의 배열간 산술연산은 배열의 각 요소 단위로 적용된다.
arr = np.array([[1.,2.,3.],[4.,5.,6.]])
arr
array([[ 1., 2., 3.], [ 4., 5., 6.]])
arr * arr
array([[ 1., 4., 9.], [ 16., 25., 36.]])
스칼라 값에 대한 산술연산
1 / arr
array([[ 1. , 0.5 , 0.33333333], [ 0.25 , 0.2 , 0.16666667]])
arr ** 0.5
array([[ 1. , 1.41421356, 1.73205081], [ 2. , 2.23606798, 2.44948974]])
색인과 슬라이싱
arr = np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr[5]
5
arr[5:8]
array([5, 6, 7])
arr[5:8] = 12
arr
array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
리스트와의 차이점은 데이터는 복사되지 않고 뷰에 대한 변경이 원본에도 반영된다!
test = list([1,2,3,4,5])
another = test[0:2]
another.append(7)
another
[1, 2, 7]
test
[1, 2, 3, 4, 5]
arr_slice = arr[5:8]
arr_slice
array([12, 12, 12])
arr_slice[1] = 12345
arr_slice
array([ 12, 12345, 12])
arr
array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8, 9])
원본의 변경을 하지 않는 슬라이스의 복사본을 얻고 싶다면 copy()를 사용해야한다.
arr_slice = arr[5:8].copy()
arr_slice
array([ 12, 12345, 12])
arr_slice[1] = 13
arr_slice, arr
(array([12, 13, 12]), array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8, 9]))
어때요 참 쉽죠?
2차원 배열에서 각 색인에 해당하는 요소는 스칼라 값이 아니라 1차원 배열
arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
arr2d
array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[2]
array([7, 8, 9])
해당 개별 요소에 접근하려면..
arr2d[2][0], arr2d[2,0]
(7, 7)
arr3d = np.arange(1,13).reshape(2,2,3)
arr3d
array([[[ 1, 2, 3], [ 4, 5, 6]], [[ 7, 8, 9], [10, 11, 12]]])
arr3d[0]
array([[1, 2, 3], [4, 5, 6]])
arr3d[0][0][0]
1
old_values = arr3d[0].copy()
arr3d[0] = 42
arr3d
array([[[42, 42, 42], [42, 42, 42]], [[ 7, 8, 9], [10, 11, 12]]])
arr3d[0] = old_values
arr3d
array([[[ 1, 2, 3], [ 4, 5, 6]], [[ 7, 8, 9], [10, 11, 12]]])
arr3d[1,0] , arr3d[1][0]
(array([7, 8, 9]), array([7, 8, 9]))
슬라이스
arr[1:6]
array([ 1, 2, 3, 4, 12])
arr2d
array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[:2]
array([[1, 2, 3], [4, 5, 6]])
색인을 여러개 넘겨서 다차원 슬라이싱을 하는것도 가능.
arr2d[:2, 1:]
array([[2, 3], [5, 6]])
arr3d[:2, :1, 1:]
array([[[2, 3]], [[8, 9]]])
arr3d
array([[[ 1, 2, 3], [ 4, 5, 6]], [[ 7, 8, 9], [10, 11, 12]]])
그냥 콜론만 쓰면 전체를 선택한다는 의미.
arr2d[: , :1], arr2d, arr2d[:]
(array([[1], [4], [7]]), array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
슬라이싱 구문에 값 대입하면 해당영역에 값이 변경
arr2d[:2, 1:]= 0
arr2d
array([[1, 0, 0], [4, 0, 0], [7, 8, 9]])
불리언 색인
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = random.randn(7,4)
names
array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='|S4')
data
array([[-0.30147523, 1.89655248, 0.7892784 , 0.7218633 ], [ 0.5805282 , 0.56840622, 0.50726692, 0.2736578 ], [-1.46632168, -1.24344615, -0.62918058, -0.87703335], [-0.72138815, 0.9121996 , -1.28514823, -0.08143278], [-1.07541291, -0.09032439, -0.75213772, 0.60409976], [ 2.06942376, 2.6797453 , -0.29314731, -0.0107111 ], [ 0.01984381, -0.24548305, 0.14152433, -0.15775719]])
각각의 이름은 data 배열의 각 row에 대응한다고 가정
예를들어 전체 로우에서 'Bob' 이름을 선택하려면 산술연산과 마찬가지로 비교연산도 벡터화된다.
names == 'Bob'
array([ True, False, False, True, False, False, False], dtype=bool)
이 불리언 배열을 색인으로 사용이 가능하다
data[names == 'Bob']
array([[-0.30147523, 1.89655248, 0.7892784 , 0.7218633 ], [-0.72138815, 0.9121996 , -1.28514823, -0.08143278]])
이 불리언 배열은 반드시 색인하려는 축의 길이와 같아야한다.
data[names=='Bob', 2:]
array([[ 0.7892784 , 0.7218633 ], [-1.28514823, -0.08143278]])
슬라이싱도 가능
data[names=='Bob', 3]
array([ 0.7218633 , -0.08143278])
names != 'Bob'
array([False, True, True, False, True, True, True], dtype=bool)
data[ -(names == 'Bob') ] , data[ ~(names == 'Bob') ]
(array([[ 0.5805282 , 0.56840622, 0.50726692, 0.2736578 ], [-1.46632168, -1.24344615, -0.62918058, -0.87703335], [-1.07541291, -0.09032439, -0.75213772, 0.60409976], [ 2.06942376, 2.6797453 , -0.29314731, -0.0107111 ], [ 0.01984381, -0.24548305, 0.14152433, -0.15775719]]), array([[ 0.5805282 , 0.56840622, 0.50726692, 0.2736578 ], [-1.46632168, -1.24344615, -0.62918058, -0.87703335], [-1.07541291, -0.09032439, -0.75213772, 0.60409976], [ 2.06942376, 2.6797453 , -0.29314731, -0.0107111 ], [ 0.01984381, -0.24548305, 0.14152433, -0.15775719]]))
-, ~ 를 사용해서 조건절을 부정할 수 있다.
논리연산자 조합
mask = (names == 'Bob') | (names == 'Will')
mask
array([ True, False, True, True, True, False, False], dtype=bool)
names
array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='|S4')
data[mask]
array([[-0.30147523, 1.89655248, 0.7892784 , 0.7218633 ], [-1.46632168, -1.24344615, -0.62918058, -0.87703335], [-0.72138815, 0.9121996 , -1.28514823, -0.08143278], [-1.07541291, -0.09032439, -0.75213772, 0.60409976]])
data[data < 0 ] = 0
data
array([[ 0. , 1.89655248, 0.7892784 , 0.7218633 ], [ 0.5805282 , 0.56840622, 0.50726692, 0.2736578 ], [ 0. , 0. , 0. , 0. ], [ 0. , 0.9121996 , 0. , 0. ], [ 0. , 0. , 0. , 0.60409976], [ 2.06942376, 2.6797453 , 0. , 0. ], [ 0.01984381, 0. , 0.14152433, 0. ]])
data[names != 'Joe'] = 7
data
array([[ 7. , 7. , 7. , 7. ], [ 0.5805282 , 0.56840622, 0.50726692, 0.2736578 ], [ 7. , 7. , 7. , 7. ], [ 7. , 7. , 7. , 7. ], [ 7. , 7. , 7. , 7. ], [ 2.06942376, 2.6797453 , 0. , 0. ], [ 0.01984381, 0. , 0.14152433, 0. ]])
arr = np.empty((8,4))
for i in range(8):
arr[i] = i
arr
array([[ 0., 0., 0., 0.], [ 1., 1., 1., 1.], [ 2., 2., 2., 2.], [ 3., 3., 3., 3.], [ 4., 4., 4., 4.], [ 5., 5., 5., 5.], [ 6., 6., 6., 6.], [ 7., 7., 7., 7.]])
특정한 순서로 row를 선택하고 싶다면 순서가 명시된 정수가 담긴 ndarray나 리스트를 넘기면 된다.
arr[[4,3,0,6]]
array([[ 4., 4., 4., 4.], [ 3., 3., 3., 3.], [ 0., 0., 0., 0.], [ 6., 6., 6., 6.]])
row = ndarray(shape=(1,4),dtype=int, buffer=np.array([1,2,3,4]))
row
array([[1, 2, 3, 4]])
arr[row]
array([[[ 1., 1., 1., 1.], [ 2., 2., 2., 2.], [ 3., 3., 3., 3.], [ 4., 4., 4., 4.]]])
arr[[-3,-5,-7]]
array([[ 5., 5., 5., 5.], [ 3., 3., 3., 3.], [ 1., 1., 1., 1.]])
arr = np.arange(32).reshape((8,4))
arr
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]])
arr[[1,5,7,2],[0,3,1,2]]
array([ 4, 23, 29, 10])
row를 선택하고 싶을땐...
arr[[1,5,7,2]]
array([[ 4, 5, 6, 7], [20, 21, 22, 23], [28, 29, 30, 31], [ 8, 9, 10, 11]])
행렬의 행과 열에 대응하는 사각형 모양의 값이 선택되기를 원한다면..
arr[[1,5,7,2]][:,[0,3,1,2]]
array([[ 4, 7, 5, 6], [20, 23, 21, 22], [28, 31, 29, 30], [ 8, 11, 9, 10]])
뒤의 0,3,1,2는 앞의 행에 대한 요소의 순서를 바꿔 놓았다.
arr[[1,5,7,2]][:]
array([[ 4, 5, 6, 7], [20, 21, 22, 23], [28, 29, 30, 31], [ 8, 9, 10, 11]])
np.ix_ 함수를 사용하면 같은 결과를 얻을 수 있다
arr[np.ix_([1,5,7,2],[0,3,1,2])]
array([[ 4, 7, 5, 6], [20, 23, 21, 22], [28, 31, 29, 30], [ 8, 11, 9, 10]])
! 팬시 색인은 슬라이싱과 달리 선택된 데이터를 새로운 배열로 복사 한다.
arr = np.arange(15).reshape((3,5))
arr
array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]])
배열 전치는 데이터를 복사하지 않고 데이터 모양이 바뀐 뷰를 반환 하는 특별한 기능
arr.T
array([[ 0, 5, 10], [ 1, 6, 11], [ 2, 7, 12], [ 3, 8, 13], [ 4, 9, 14]])
행렬의 내적은 np.dot을 이용해 구할 수 있다.
arr = np.arange(4).reshape((2,2))
arr
array([[0, 1], [2, 3]])
np.dot(arr.T,arr)
array([[ 4, 6], [ 6, 10]])
행렬의 곱이 된다는걸 알 수 있다.
다차원 배열의 경우 transpose 메서드는 튜플로 축 번호를 받아서 치환.
arr = np.arange(16).reshape((2,2,4))
arr
array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7]], [[ 8, 9, 10, 11], [12, 13, 14, 15]]])
arr.transpose((1,0,2))
array([[[ 0, 1, 2, 3], [ 8, 9, 10, 11]], [[ 4, 5, 6, 7], [12, 13, 14, 15]]])
arr.transpose()
array([[[ 0, 8], [ 4, 12]], [[ 1, 9], [ 5, 13]], [[ 2, 10], [ 6, 14]], [[ 3, 11], [ 7, 15]]])
ndarray에는 swapaxes 메서드가 있는데 2개의 축 번호를 받아서 배열을 뒤바꾼다.
arr
array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7]], [[ 8, 9, 10, 11], [12, 13, 14, 15]]])
arr.swapaxes(1,2)
array([[[ 0, 4], [ 1, 5], [ 2, 6], [ 3, 7]], [[ 8, 12], [ 9, 13], [10, 14], [11, 15]]])
유니버설 함수 : ufunc라고도 불리며, ndarray안에 있는 데이터 원소별로 연산을 수행하는 함수다.
유니버설 함수는 하나 이상의 스칼라 값을 받아서 하나 이상의 스칼라 결과 값을 반환한다.
arr = np.arange(10)
np.sqrt(arr)
array([ 0. , 1. , 1.41421356, 1.73205081, 2. , 2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ])
np.exp(arr)
array([ 1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01, 5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03, 2.98095799e+03, 8.10308393e+03])
이러너 함수를 단항 유니버설 함수라고 하고, add 나 maximum 처럼 2개의 인자를 취하는 함수는 이항유니버설 함수
x = randn(8)
y = randn(8)
x
array([ 0.91366058, -0.21049552, 0.88583422, 0.70849776, 0.28146527, 1.3771023 , 1.32168366, -0.99986874])
y
array([-0.33964315, 0.25799327, -1.92523521, 0.96830099, -0.20384351, 0.3392212 , 0.2370621 , -0.73755944])
np.maximum(x,y)
array([ 0.91366058, 0.25799327, 0.88583422, 0.96830099, 0.28146527, 1.3771023 , 1.32168366, -0.73755944])
maximum은 각각의 값을 비교하여 큰 값을 둘 중 큰 값을 배열로 채워넣는다
modf 함수는 분수를 받아 몫과 나머지를 함께 반환한다.
arr = randn(7) * 5
arr
array([ 1.10132321, 0.5817882 , 12.32166227, -0.02476515, -7.08652897, 1.67633894, -1.88749467])
np.modf(arr)
(array([ 0.10132321, 0.5817882 , 0.32166227, -0.02476515, -0.08652897, 0.67633894, -0.88749467]), array([ 1., 0., 12., -0., -7., 1., -1.]))
배열을 사용한 데이터 처리
Numpy 배열을 사용하면 반복문을 사용하지 않고 간결한 배열연산을 통해 많은 종류의 데이터처리 가능
배열연산을 사용해서 반복문을 명시적으로 제거하는 기법을 흔히 벡터화 라 한다.
points = np.arange(-5,5,0.01)
xs, ys = np.meshgrid(points, points)
ys
array([[-5. , -5. , -5. , ..., -5. , -5. , -5. ], [-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99], [-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98], ..., [ 4.97, 4.97, 4.97, ..., 4.97, 4.97, 4.97], [ 4.98, 4.98, 4.98, ..., 4.98, 4.98, 4.98], [ 4.99, 4.99, 4.99, ..., 4.99, 4.99, 4.99]])
z = np.sqrt( xs ** 2 + ys ** 2)
z
array([[ 7.07106781, 7.06400028, 7.05693985, ..., 7.04988652, 7.05693985, 7.06400028], [ 7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815, 7.05692568], [ 7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354, 7.04985815], ..., [ 7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 , 7.03571603, 7.04279774], [ 7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354, 7.04985815], [ 7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815, 7.05692568]])
배열연산으로 조건절 표현하기
umpy.whrer 함수는 x if 조건 else y 같은 삼항식의 벡터화된 버전이다.
xarr = np.array([1.1,1.2,1.3,1.4,1.4])
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
[1.1000000000000001, 2.2000000000000002, 1.3, 1.3999999999999999, 2.5]
위 와 같은 방법에는 순수 파이썬으로 동작하기에 큰 배열을 빠르게 처리하지 못한다는 문제가 있다. np.where를 사용하면 아주 간결해진다.
result = np.where(cond, xarr, yarr)
result
array([ 1.1, 2.2, 1.3, 1.4, 2.5])
arr = np.random.randn(4,4)
arr
array([[ 2.36950006, -1.62238951, 2.01426591, -2.04313633], [ 0.95044658, -1.66868802, -0.81504954, -1.3844996 ], [-0.02542584, -0.77171878, -0.62249086, 0.43455851], [ 0.26702506, 0.41811052, 0.21094843, 0.75440271]])
np.where( arr > 0, 2, -2)
array([[ 2, -2, 2, -2], [ 2, -2, -2, -2], [-2, -2, -2, 2], [ 2, 2, 2, 2]])
np.where( arr > 0, 2, arr )
array([[ 2. , -1.62238951, 2. , -2.04313633], [ 2. , -1.66868802, -0.81504954, -1.3844996 ], [-0.02542584, -0.77171878, -0.62249086, 2. ], [ 2. , 2. , 2. , 2. ]])
수학 메서드와 통계 메서드
sum(합), mean(평균), std(표준편차)
arr = np.random.randn(5,4)
arr.mean()
-0.032396737517465621
np.mean(arr)
-0.032396737517465621
arr.sum()
-0.64793475034931247
np array axis=0 은 column axis=1은 row
arr.mean(axis=1)
array([-0.06665352, -0.26758776, 0.16051497, 0.15412104, -0.14237842])
arr.sum(0)
array([ 1.49212796, -0.45619855, -0.23557768, -1.44828649])
cumsum과 cumprod 메서드는 중간 계산 값을 담고 있는 배열을 반환
arr = np.array([[0,1,2],[3,4,5],[6,7,8]])
arr
array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
arr.cumsum(0)
array([[ 0, 1, 2], [ 3, 5, 7], [ 9, 12, 15]])
arr.cumprod(1)
array([[ 0, 0, 0], [ 3, 12, 60], [ 6, 42, 336]])
불리언 배열을 위한 메서드
arr = randn(100)
(arr>0).sum()
43
any 메서드는 하나 이상의 True를 검사, all은 모든 원소가 True인지 검사
bools = np.array([False, False, True, False])
bools.any()
True
bools.all()
False
이 메서드는 불리언 배열이 아니어도 동작하며, 0이 아닌 원소는 모두 True로 간주
정렬
arr = np.random.randn(8)
arr
array([ 1.41400814, 0.29185882, -0.05540911, 0.62555065, 0.84990579, -0.57336542, 0.92216407, -1.14059269])
arr.sort()
arr
array([-1.14059269, -0.57336542, -0.05540911, 0.29185882, 0.62555065, 0.84990579, 0.92216407, 1.41400814])
다차원 배열의 정렬은 sort메서드에 넘긴 축의 값에 따라 1차원 부분을 정렬
arr = randn(5,3)
arr
array([[ 0.41311489, 1.33220697, -0.14320923], [-0.26442777, -0.56870091, 0.05582757], [ 1.38141784, 0.8922349 , 0.00437634], [-0.51040168, 0.72019665, -1.4914916 ], [ 1.11054408, 0.76414898, 1.47842511]])
arr.sort(1)
arr
array([[-0.14320923, 0.41311489, 1.33220697], [-0.56870091, -0.26442777, 0.05582757], [ 0.00437634, 0.8922349 , 1.38141784], [-1.4914916 , -0.51040168, 0.72019665], [ 0.76414898, 1.11054408, 1.47842511]])
arr.sort(0)
arr
array([[-1.4914916 , -0.51040168, 0.05582757], [-0.56870091, -0.26442777, 0.72019665], [-0.14320923, 0.41311489, 1.33220697], [ 0.00437634, 0.8922349 , 1.38141784], [ 0.76414898, 1.11054408, 1.47842511]])
np.sort는 배열을 직접 변경하지 않고, 정렬된 결과를 가지고 있는 복사본을 반환
large_arr = randn(100)
large_arr.sort()
large_arr[int(0.05 * len(large_arr))]
-1.2122853132733646
집합 함수
중복된 원소를 제거하고 정렬된 형태로 반환하는 np.unique
names = np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
np.unique(names)
array(['Bob', 'Joe', 'Will'], dtype='|S4')
ints = np.array([3,3,3,2,2,1,1,4,4,])
np.unique(ints)
array([1, 2, 3, 4])
np.unique를 순수 파이썬로 구현하면 다음과 같다.
sorted(set(names))
['Bob', 'Joe', 'Will']
np.in1d 함수는 2개의 배열을 인자로 받아 첫 번째 배열의 각 원소가 두 번째 배열의 원소를 포함하는지 나타내는 불리언 배열을 반환
values = np.array([6,0,0,3,2,5,6])
np.in1d(values,[2,3,6])
array([ True, False, False, True, True, False, True], dtype=bool)
배열의 파일 입출력
배열을 바이너리 형식으로 디스크에 저장하기
np.save 와 np.load는 배열 데이터를 효과적으로 디스크에 저장, 불러오는 함수다. 배열은 기본적으로 압축되지 않은 raw 바이너리 형식의 .npy파일로 저장
arr = np.arange(10)
np.save('some_array',arr)
!ls
ch2_case.ipynb ch4_numpy.ipynb README.md some_array.npy
np.load로 불러올수 있다.
np.load('some_array.npy')
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.savez 함수를 이용하면 여러 개의 배열을 압축된 형식으로 저장가능
저장하려는 배열은 키워드 인자 형태로 전달된다
np.savez('array_archive',a=arr, b1=arr)
!ls
array_archive.npz ch2_case.ipynb ch4_numpy.ipynb README.md some_array.npy
arch = np.load('array_archive.npz')
arch['b1'], arch['a']
(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
텍스트 파일 불러오기와 저장하기
!cat array_ex.txt
cat: array_ex.txt: No such file or directory
arr = np.loadtxt('array_ex.txt', delimiter=',')
--------------------------------------------------------------------------- IOError Traceback (most recent call last) <ipython-input-196-9f226c01d765> in <module>() ----> 1 arr = np.loadtxt('array_ex.txt', delimiter=',') /BIO/home/moodern/.venv/total/local/lib/python2.7/site-packages/numpy/lib/npyio.pyc in loadtxt(fname, dtype, comments, delimiter, converters, skiprows, usecols, unpack, ndmin) 735 fh = iter(bz2.BZ2File(fname)) 736 elif sys.version_info[0] == 2: --> 737 fh = iter(open(fname, 'U')) 738 else: 739 fh = iter(open(fname)) IOError: [Errno 2] No such file or directory: 'array_ex.txt'
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.savetxt('array_ex2.txt',arr,delimiter=',')
arr2 = np.loadtxt('array_ex2.txt',delimiter=',')
arr2
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
선형대수
행렬의 곱셈, 분할, 행렬식, 정사각 행렬 수학 같은 선형대수는 배열을 다루는 라이브러리에서 중요한 부분
두 행렬간의 곱셈을 할 경우 * 를 쓰게되면 행렬 곱셈이 아니라 대응하는 각각의 원소의 곱을 계산 하는 것
행렬의 곱셈을 하려면 dot 함수를 써야 한다.
x = np.array([[1.,2.,3.],[4.,5.,6.]])
y = np.array([[6.,23.],[-1,7],[8,9]])
x
array([[ 1., 2., 3.], [ 4., 5., 6.]])
y
array([[ 6., 23.], [ -1., 7.], [ 8., 9.]])
x.dot(y)
array([[ 28., 64.], [ 67., 181.]])
2차원 배열과 곱셈이 가능한 크기의 1차원 배열 간 행렬 곱셈 결과는 1차원 배열이다.
np.dot(x,np.ones(3))
array([ 6., 15.])
numpy.linalg( Linear algebra )는 행렬의 분할과 역행렬, 행렬식 같은것을 포함하고 있다.
from numpy.linalg import inv, qr
X = np.arange(4).reshape((2,2))
mat = X.T.dot(X)
mat
array([[ 4, 6], [ 6, 10]])
inv(mat)
array([[ 2.5, -1.5], [-1.5, 1. ]])
mat.dot(inv(mat))
array([[ 1., 0.], [ 0., 1.]])
q, r = qr(mat)
q
array([[-0.5547002 , -0.83205029], [-0.83205029, 0.5547002 ]])
r
array([[ -7.21110255, -11.64870412], [ 0. , 0.5547002 ]])
난수 생성
numpy.random 모듈은 파이썬 내장 random 함수를 보강하여 다양한 종류의 확률분포로부터 효과적으로 표본 값을 생성하는 데 주로 사용된다.
normal을 사용하여 표준정규 분포로부터 4x4 표본 생성하기
samples = np.random.normal(size=(4,4))
samples
array([[ 1.66407184, 0.14709756, 0.77541292, 0.29011476], [ 0.45743633, -0.3563855 , -0.93134658, 1.6674781 ], [ 0.88954633, -0.03404718, 1.58524112, 0.3129696 ], [-1.15179727, 1.60451562, 0.35874296, -0.92453313]])
이에 비해 파이썬 내장 random 모듈은 한 번에 하나의 값만 생성할 수 있다.
from random import normalvariate
N = 1000000
%timeit samples = [normalvariate(0,1) for _ in xrange(N)]
1 loops, best of 3: 1.11 s per loop
%timeit np.random.normal(size=N)
10 loops, best of 3: 57.9 ms per loop
계단 오르내리기 예제
import random
position = 0
walk = [position]
steps = 100
for i in xrange(steps):
step = 1 if random.randint(0,1) else -1
position += step
walk.append(position)
plt.plot(walk)
[<matplotlib.lines.Line2D at 0x4618d10>]
nsteps = 1000
draws = np.random.randint(0,2,size=nsteps)
steps = np.where(draws > 0, 1, -1)
walk = steps.cumsum()
walk.min(), walk.max()
(-13, 26)
처음 위치에서 10칸 이상 떨어진 시점을 알아보기. 최초의 10 혹은 -10인 시점을 구해야 하므로 불리언 배열에서 최대 값의 처음 색인을 반환하는 argmax 사용
(np.abs(walk) >= 10).argmax()
27
nwalks = 5000
nsteps = 1000
draws = np.random.randint(0,2,size=(nwalks,nsteps))
steps = np.where(draws > 0 , 1, -1)
walks = steps.cumsum(1)
walks
array([[ 1, 0, 1, ..., 24, 23, 22], [ 1, 0, 1, ..., 8, 9, 8], [ 1, 0, 1, ..., -24, -23, -22], ..., [ -1, -2, -1, ..., -22, -23, -22], [ 1, 2, 1, ..., -12, -11, -10], [ 1, 2, 3, ..., -24, -23, -24]])
walks.max(), walks.min()
(120, -107)
hist30 = (np.abs(walks) >= 30).any(1)
hist30
array([ True, True, False, ..., True, False, False], dtype=bool)
hist30.sum()
3450