<jupyter_start><jupyter_text>1. Numerial Python - Numpy- 어떻게 수식을 코드로 표현할 것인가?  코드로 방정식 표현하기<jupyter_code>coefficient_matrix = [[2, 2, 1], [2, -1, 2], [1, -1, 2]]
constant_vector = [9, 6, 5]<jupyter_output><empty_output><jupyter_text>하지만 위의 코드처럼 표현할 때 문제가 생김- 다양한 Matrix 계산을 어떻게 만들 것인가?- 굉장히 큰 Matrix에 대한 표현- 처리 속도 문제(파이썬은 Interpreter 언어 - 여기서 인터프리터(interpreter)는 프로그래밍 언어의 소스 코드를 바로 실행하는 컴퓨터 프로그램 또는 환경을 말한다.따라서 적절한 패키지를 활용하는 것이 좋은 방법  Numpy이란?- Numerical Python- 파이썬의 고성능 과학 계산용 패키지- Matrix와 Vector와 같은 Array 연산의 사실상 표준- 한글로 넘파이로 주로 통칭, 넘피/늄파이라고 부르기도 함  Numpy 특징- 일반 List에 비해 빠르고(C언어로 짜여져 있음), 메모리 효율성이 높음- 반복문(for문이나 list compression) 없이 데이터 배열에 대한 처리를 지원함- 선형대수와 관련된 다양한 기능을 제공함- C, C++, 포트란 등의 언어와 통합 가능 ---  2. Ndarray  Numpy import- numpy의 호출 방법- 일반적으로 numpy는 np라는 alias(별칭)를 이용해서 호출함- 특별한 이유는 없음. 세계적인 약속 같은 것 설치는 아래와 같이 하면 됨- pip install numpy<jupyter_code>import numpy as np<jupyter_output><empty_output><jupyter_text>Array creation- numpy는 np.array 함수를 활용하여 배열을 생성함 -> ndarray (n-dimension array)- numpy는 하나의 데이터 type만 배열에 넣을 수 있음- List와 가장 큰 차이점, Dynamic typing not supported- C의 Array를 사용하여 배열을 생성함추가적으로 Dynamic typing이란, 파이썬에서는 실행시점에서 데이터 타입을 결정하기 때문에 다양한 데이터 타입이 리스트에 들어갈 수 있다. 그러니까 메모리에 공간을 처음 시작할 때 잡아두는 것이 아니라 계속해서 추가할 수 있도록 되어있기 때문에 하나의 리스트에도 다양한 타입들이 들어갈 수가 있다.하지만 numpy는 이것을 허락하지 않는다. 그래서 밑의 코드와 같이 str 자료형과 int 자료형이 들어가도 float로 선언을 했기 때문에 출력을 했을 때 float 자료형으로서 뒤에 .이 붙어서 나오는 것을 볼 수 있다. 이러한 점이 기존의 list와 numpy ndarray의 가장 큰 차이점이다.<jupyter_code>test_array = np.array(["1", "4", 5, 8], float)
test_array
print(test_array)
type(test_array)
type(test_array[1])<jupyter_output><empty_output><jupyter_text>여기서 64는 비트의 수를 말한다. 다시 말해 하나의 element가 차지하는 메모리의 공간이 64 비트인 것이다.이번에는 32비트로 지정하여 출력해보자.<jupyter_code>test_array = np.array([1, 4, 5, "8"], np.float32)
test_array
print(test_array)
type(test_array)
type(test_array[1])<jupyter_output><empty_output><jupyter_text>다음으로 아래의 그림을 보자.  Python List의 경우 바로 그 list를 가리키는 것이 아니라 메모리의 주소를 가리키게 된다. 그래서 어떠한 리스트를 복사할 때 우리는 [:]를 이용하거나 import copy를 이용해야만 했다.하지만 Numpy Array는 메모리의 주소를 가리키는 것이 아니라 데이터를 쌓게 되고, 직접적으로 그 데이터를 가리킨다. 그래서 연산이 더 빠르다. 다음으로 기본적인 내용들을 정리해보자.<jupyter_code>test_array = np.array([[1, 4, 5, "8"], [3, 5, 6, 7]], float)
print(test_array)
print(type(test_array[0][3]))
print(test_array.shape)
print(test_array.dtype)<jupyter_output>[[1. 4. 5. 8.]
 [3. 5. 6. 7.]]
<class 'numpy.float64'>
(2, 4)
float64<jupyter_text>- shape : numpy array의 object의 dimension 구성을 반환함(튜플 타입으로 반환)- dtype : numpy array의 데이터 type을 반환함  Array shape - Vector<jupyter_code>vector  = [1,2,3,4]
print(np.array(vector, float).shape)<jupyter_output>(4,)<jupyter_text>- Matrix<jupyter_code>matrix  = [[1,2,5,8],[1,2,5,8],[1,2,5,8]]
print(np.array(matrix, float).shape)<jupyter_output>(3, 4)<jupyter_text>- 3rd Order Tensor<jupyter_code>tensor  = [[[1,2,5,8],[1,2,5,8],[1,2,5,8]], 
           [[1,2,5,8],[1,2,5,8],[1,2,5,8]], 
           [[1,2,5,8],[1,2,5,8],[1,2,5,8]], 
           [[1,2,5,8],[1,2,5,8],[1,2,5,8]]]
print(np.array(tensor, float).shape)<jupyter_output>(4, 3, 4)<jupyter_text>보면 한칸 씩 밀리는 것을 볼 수 있다. 그러니까 vector일 때는 (4,), matrix일 때는 (3,4), tensor일 때는 (4,3,4)처럼 한칸 씩 밀린다. 이렇게 표현하는 법을 잘 알아두자.여기서 또 중요한 것이 두 가지가 있다.- ndim : number of dimension- size : data의 개수<jupyter_code>print(np.array(tensor, float).ndim)
print(np.array(tensor, float).size)<jupyter_output>3
48<jupyter_text>Array dtype- ndarray의 single element가 가지는 data type- 각 element가 차지하는 memory의 크기가 결정됨보통은 float32, float64를 많이 사용한다. 또한 float64를 float라고 써도 같은 의미이다.<jupyter_code>np.array([[1, 2, 3], [4.5, 5, 6]], dtype=int)<jupyter_output><empty_output><jupyter_text>그리고 기본적으로 dtype을 정해주지 않으면 float64로 설정된다.<jupyter_code>np.array([[1, 2, 3], [4.5, 5, 6]])
np.array([[1, 2, 3], [4.5, "5", "6"]], dtype=np.float32)
np.array([[1, 2, 3], [4.5, "5", "6"]], dtype=np.float32).nbytes<jupyter_output><empty_output><jupyter_text>하나의 element당 32bits = 4bytes -> 4 * 6 bytes<jupyter_code>np.array([[1, 2, 3], [4.5, "5", "6"]], dtype=np.int8).nbytes<jupyter_output><empty_output><jupyter_text>하나의 element당 8bits = 1bytes -> 1 * 6 bytes<jupyter_code>np.array([[1, 2, 3], [4.5, "5", "6"]], dtype=np.float64).nbytes<jupyter_output><empty_output><jupyter_text>하나의 element당 64bits = 8bytes -> 8 * 6 bytes ---  3. Handling shape  reshape- Array의 shape의 크기를 변경함(element의 갯수는 동일)<jupyter_code>test_matrix = [[1,2,3,4], [1,2,5,8]]
print(np.array(test_matrix, float).shape)
print(np.array(test_matrix).reshape(8)) # 하나만 넣으면 column 지정<jupyter_output>[1 2 3 4 1 2 5 8]<jupyter_text><jupyter_code>print(np.array(test_matrix).reshape(2,2,2))
print(np.array(test_matrix).reshape(-1,2))<jupyter_output>[[1 2]
 [3 4]
 [1 2]
 [5 8]]<jupyter_text>내가 column값만 지정하고 나머지는 별로 신경쓰고 싶지 않을 때 또는 row의 갯수를 정확하게 모를 때, -1로 하여 size를 기반으로 row 개수를 선정해준다. 쉽게 말해 "열만 2로 하고 싶고, 나머지는 너가 알아서 해줘"라는 것이다.또한 reshape은 보다시피 총 element의 갯수가 만약 8이라면 8의 약수로만 reshape을 할 수 있고, -1로 할 때도 마찬가지이다.그래서 다음의 두 코드는 서로 같게 된다.<jupyter_code>print(np.array(test_matrix).reshape(2,4))
print(np.array(test_matrix).reshape(2,4).shape)
print(np.array(test_matrix).reshape(2,-1))
print(np.array(test_matrix).reshape(2,-1).shape)<jupyter_output>[[1 2 3 4]
 [1 2 5 8]]
(2, 4)<jupyter_text>flat or flatten()- 다차원 array를 1차원 array로 변환<jupyter_code>test_matrix = [[[1,2,3,4], [1,2,5,8]], [[1,2,3,4], [1,2,5,8]]]
print(np.array(test_matrix).shape)
print(np.array(test_matrix).flatten())<jupyter_output>[1 2 3 4 1 2 5 8 1 2 3 4 1 2 5 8]<jupyter_text>---  4. Indexing & Sclicing  Indexing- List와 달리 이차원 배열에서 [0,0] 과 같은 표기법을 제공함- Matrix일 경우 앞은 row 뒤는 column을 의미함<jupyter_code>test_example = np.array([[1, 2, 3], [4, 5, 6]], float)
print(test_example)
print(test_example[0][0])
print(test_example[0,0])
test_example[0,0] = 10 # Matrix 0,0에 10 할당
print(test_example)
test_example[0][0] = 5 # Matrix 0,0에 5 할당
print(test_example[0,0])<jupyter_output>5.0<jupyter_text>Slicing- List와 달리 행과 열 부분을 나눠서 slicing이 가능함- Matrix의 부분 집합을 추출할 때 유용함<jupyter_code>test_example = np.array([[1,2,5,8],[1,3,6,9],[1,4,7,10],[1,2,3,4]], float)
print(test_example[:2,:])
print(test_example[:,1:3])
print(test_example[1,:2])
test_example = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]], float)
print(test_example[:,2:])
a = np.arange(100).reshape(10,10)
print(a[:, -1])
print(a[:, -1].reshape(-1,1))<jupyter_output>[ 9 19 29 39 49 59 69 79 89 99]
[[ 9]
 [19]
 [29]
 [39]
 [49]
 [59]
 [69]
 [79]
 [89]
 [99]]<jupyter_text>slicing할 때도 위와 같이 -1로 하여 나눌 수 있다. 이 때의 -1은 앞서 다뤘던 "알아서 너가 해줘"의 의미가 아니라 matrix에서 가장 맨 뒤에 있는 열을 의미한다. ---  5. Creation function  arange- array의 범위를 지정하여, 값의 list를 생성하는 명령어(기본적으로 int형으로 생성됨)<jupyter_code>np.arange(30, dtype=float).reshape(-1,5)
np.arange(0, 5, 0.5)
np.arange(30).reshape(5,6)<jupyter_output><empty_output><jupyter_text>ones, zeros & empty- zeros – 0으로 가득찬 ndarray 생성<jupyter_code>print(np.zeros(shape=(10,), dtype=np.int8)) # 10 - zero vector 생성
print(np.zeros((2,5), float)) # 2 by 5 - zero matrix 생성<jupyter_output>[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]<jupyter_text>- ones – 1로 가득찬 ndarrary 생성<jupyter_code>print(np.ones(shape=(10,), dtype=np.int8) )
print(np.ones((5,2)))<jupyter_output>[[1. 1.]
 [1. 1.]
 [1. 1.]
 [1. 1.]
 [1. 1.]]<jupyter_text>- empty – shape만 주어지고 비어있는 ndarray 생성 (memory initialization 이 되지 않음)메모리 공간은 잡는 대신 숫자로 초기화를 시켜주지 않으면 이상한 값들이 들어가있게 된다.<jupyter_code>print(np.empty(shape=(10,), dtype=np.int8))
print(np.empty((3,5)))<jupyter_output>[[0.00000000e+000 0.00000000e+000 3.95252517e-323 0.00000000e+000
  0.00000000e+000]
 [0.00000000e+000 0.00000000e+000 0.00000000e+000 0.00000000e+000
  0.00000000e+000]
 [0.00000000e+000 0.00000000e+000 0.00000000e+000 0.00000000e+000
  1.49457494e-154]]<jupyter_text>something_like- 기존 ndarray의 shape 크기 만큼 1, 0 또는 empty array를 반환<jupyter_code>test_matrix = np.arange(30).reshape(5,6)
print(test_matrix)
print(np.zeros_like(test_matrix))<jupyter_output>[[ 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]]
[[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]]<jupyter_text>identity- 단위 행렬(i 행렬)을 생성함<jupyter_code>print(np.identity(n=3, dtype=np.int8))
print(np.identity(5))<jupyter_output>[[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]<jupyter_text>eye- 대각선이 1인 행렬, k값의 시작 index의 변경이 가능<jupyter_code>print(np.eye(N=3, M=5, dtype=np.int8))
print(np.eye(3))
print(np.eye(3,5,k=2))<jupyter_output>[[0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]<jupyter_text>diag- 대각 행렬의 값을 추출함<jupyter_code>matrix = np.arange(9).reshape(3,3)
print(matrix)
print(np.diag(matrix))
print(np.diag(matrix, k=1))<jupyter_output>[1 5]<jupyter_text>random sampling- 데이터 분포에 따른 sampling으로 array를 생성 np.random.uniform(x,y,z)는 x 이상부터 y 미만사이의 z개를 Uniform distribution random 값으로 선언<jupyter_code>print(np.random.uniform(0,1,10).reshape(2,5))<jupyter_output>[[0.05304743 0.95291467 0.60984087 0.50002365 0.09317442]
 [0.35434932 0.49591917 0.33553849 0.26153455 0.90751697]]<jupyter_text>np.random.normal(x,y,z)는 x 이상부터 y 미만 사이의 z개를 평균이 0이고 분산이 1인 Normal distribution random 값으로 선언<jupyter_code>print(np.random.normal(0,1,10).reshape(2,5))<jupyter_output>[[-0.67144465  0.19517173 -0.85120866 -1.09597542  1.71868698]
 [ 0.99824131  0.68558982 -0.82169918 -0.84966682  0.01234715]]<jupyter_text>---  6. Operation functions  sum- ndarray의 element들 간의 합을 구함, list의 sum 기능과 동일<jupyter_code>test_array = np.arange(1,11)
print(test_array)
print(test_array.sum(dtype=np.float))
print(test_array.sum(dtype=float))
print(test_array.sum())
test_array = np.arange(1,13).reshape(3,4)
print(test_array.sum())<jupyter_output>78<jupyter_text>axis- 모든 operation function을 실행할 때, 기준이 되는 dimension 축  쉽게 말해 axis가 늘어날수록 더 낮은 dimension 축이 설정된다. 이것만 기억하자. axis = 0이 제일 큰 축, 제일 큰 숫자가 제일 작은 축이다. 그래서 구분하는 법은 그 축에 해당되는 라인을 찾고 그 라인대로 회오리를 그려본 뒤에 계산을 하면 된다. 앞서 다뤘던 reshape과 햇갈리면 안된다.<jupyter_code>print(test_array.sum(axis=1))
print(test_array.sum(axis=0))
print(test_array.sum(axis=-1)) # axis가 가장 큰 수 & 가장 낮은 dimension 축<jupyter_output>[10 26 42]<jupyter_text><jupyter_code>third_order_tensor = np.array([test_array,test_array,test_array])
print(third_order_tensor)
print(third_order_tensor.shape)
print(third_order_tensor.sum(axis=2))
print(third_order_tensor.sum(axis=1))
print(third_order_tensor.sum(axis=0))
print(third_order_tensor.sum(axis=-1))<jupyter_output>[[10 26 42]
 [10 26 42]
 [10 26 42]]<jupyter_text>mean & std- ndarray의 element들 간의 평균 또는 표준 편차를 반환<jupyter_code>test_array = np.arange(1,13).reshape(3,4)
print(test_array)
print(test_array.mean(), test_array.mean(axis=0))
print(test_array.std(), test_array.std(axis=0))<jupyter_output>3.452052529534663 [3.26598632 3.26598632 3.26598632 3.26598632]<jupyter_text>Mathematical functions- exponential : exp($e^x$), expm1($e^x -1$), exp2($2^x$), log($\log_{e} x$ or $ln x$), log10($\log_{10} x$), log1p($\log_{e} x+1$, expm1의 inverse), log2($\log_{2} x$), power($x^2$), sqrt($\sqrt{x}$)- trigonometric : sin, cos, tan, acsin, arccos, atctan- hyperbolic : sinh, cosh, tanh, acsinh, arccosh, atctanh- 그 외에도 다양한 수학 연산자를 제공함 (np.something 호출)<jupyter_code>print(np.exp(test_array))
print(np.sqrt(test_array))<jupyter_output>[[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 2.20264658e+04 5.98741417e+04 1.62754791e+05]]
[[1.         1.41421356 1.73205081 2.        ]
 [2.23606798 2.44948974 2.64575131 2.82842712]
 [3.         3.16227766 3.31662479 3.46410162]]<jupyter_text>concatenate- Numpy array를 합치는 함수<jupyter_code>a = np.array([1, 2, 3])
b = np.array([2, 3, 4])
print(np.vstack((a,b)))
a = np.array([[1], [2], [3]])
b = np.array([[2], [3], [4]])
print(np.hstack((a,b)))<jupyter_output>[[1 2]
 [2 3]
 [3 4]]<jupyter_text><jupyter_code>a = np.array([[1, 2, 3]])
b = np.array([[2, 3, 4]])
print(np.concatenate((a,b), axis=0))
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
print(np.concatenate((a,b.T), axis=1)) # 여기서 T는 transpose
print(np.concatenate((a, b), axis=None)) # flatten과 동일<jupyter_output>[1 2 3 4 5 6]<jupyter_text>---  7. Array operations  Operations b/t arrays- Numpy는 array간의 기본적인 사칙 연산을 지원함<jupyter_code>test_a = np.array([[1,2,3],[4,5,6]], float)
print(test_a + test_a) # Matrix + Matrix 연산
print(test_a - test_a) # Matrix - Matrix 연산
print(test_a * test_a) # Matrix내 element들 간 같은 위치에 있는 값들끼리 연산<jupyter_output>[[ 2.  4.  6.]
 [ 8. 10. 12.]]
[[0. 0. 0.]
 [0. 0. 0.]]
[[ 1.  4.  9.]
 [16. 25. 36.]]<jupyter_text>Element-wise operations- Array간 shape이 같을 때 일어나는 연산<jupyter_code>matrix_a = np.arange(1,13).reshape(3,4)
print(matrix_a * matrix_a)<jupyter_output>[[  1   4   9  16]
 [ 25  36  49  64]
 [ 81 100 121 144]]<jupyter_text>Dot product- Matrix의 기본 연산- dot 함수 사용<jupyter_code>test_a = np.arange(1,7).reshape(2,3)
test_b = np.arange(7,13).reshape(3,2)
print(test_a.dot(test_b))<jupyter_output>[[ 58  64]
 [139 154]]<jupyter_text>transpose- transpose 또는 T attribute 사용<jupyter_code>test_a = np.arange(1,7).reshape(2,3)
print(test_a)
print(test_a.transpose())
print(test_a.T)
print(test_a.T.dot(test_a))<jupyter_output>[[17 22 27]
 [22 29 36]
 [27 36 45]]<jupyter_text>broadcasting- Shape이 다른 배열 간 연산을 지원하는 기능<jupyter_code>test_matrix = np.array([[1,2,3],[4,5,6]], float)
scalar = 3
print(test_matrix + scalar) # Matrix - Scalar 덧셈
print(test_matrix - scalar) # Matrix - Scalar 뺄셈
print(test_matrix * 5) # Matrix - Scalar 곱셈
print(test_matrix / 5) # Matrix - Scalar 나눗셈
print(test_matrix // 2) # Matrix - Scalar 몫
print(test_matrix % 2) # Matrix - Scalar 나머지
print(test_matrix ** 2) # Matrix - Scalar 제곱<jupyter_output>[[ 1.  4.  9.]
 [16. 25. 36.]]<jupyter_text>Numpy performance- 일반적으로 속도는 "for loop < list comprehension < numpy"- 100,000,000번의 loop이 돌 때 약 4배 이상의 성능 차이를 보임- Numpy는 C로 구현되어 있어, 성능을 확보하는 대신- 파이썬의 가장 큰 특징인 dynamic typing을 포기함- 대용량 계산에서는 가장 흔히 사용됨- Concatenate 처럼 계산이 아닌, 할당에서는 연산 속도의 이점이 없음 - timeit: jupyter 환경에서 코드의 퍼포먼스를 체크하는 함수<jupyter_code>def sclar_vector_product(scalar, vector):
    result = []
    for value in vector:
        result.append(scalar * value)
    return result 

iternation_max = 10000

vector = list(range(iternation_max))
scalar = 2

%timeit sclar_vector_product(scalar, vector) # for loop을 이용한 성능
%timeit [scalar * value for value in range(iternation_max)] # list comprehension을 이용한 성능
%timeit np.arange(iternation_max) * scalar # numpy를 이용한 성능<jupyter_output>750 µs ± 5.17 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
8.87 µs ± 27.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)<jupyter_text>---  8. Comparisons  All & Any- Array의 데이터 전부(and) 또는 일부(or)가 조건에 만족 여부 반환<jupyter_code>a = np.arange(10)
print(a)
print(a>5)
print(np.all(a>5), np.all(a<10))
print(np.any(a>5), np.any(a<0))<jupyter_output>True False<jupyter_text>Comparison operation- Numpy는 배열의 크기가 동일 할 때 element간 비교의 결과를 Boolean type으로 반환하여 돌려줌<jupyter_code>test_a = np.array([1, 3, 0], float)
test_b = np.array([5, 2, 1], float)
print(test_a > test_b)
print(test_a == test_b)
print((test_a > test_b).any())<jupyter_output>True<jupyter_text>다음으로 거의 잘 쓰진 않는데 logical에 대해서도 알아보자.<jupyter_code>a = np.array([1, 3, 0], float)
print(np.logical_and(a > 0, a < 3)) # AND 조건의 condition
b = np.array([True, False, True])
print(np.logical_not(b)) # NOT 조건의 condition
c = np.array([False, True, False])
print(np.logical_or(b, c)) # OR 조건의 condition<jupyter_output>[ True  True  True]<jupyter_text>np.where- np.where(x) : x의 조건에 따른 index 값을 반환- np.where(x, y, z) : x의 조건을 index에 따라서 True일 경우 y, False일 경우 z를 반환<jupyter_code>a = np.array([1, 3, 0], float)
print(np.where(a>0, 3, 2))
print(np.where(a>0))
a = np.arange(5, 15)
print(a)
print(np.where(a>10))
a = np.array([1, np.NaN, np.Inf], float)
print(np.isnan(a))<jupyter_output>[False  True False]<jupyter_text>- Nan : null값- Inf : infinity값<jupyter_code>print(np.isfinite(a))<jupyter_output>[ True False False]<jupyter_text>argmax & argmin- array내 최댓값 또는 최솟값의 index를 반환함- axis 기반의 반환<jupyter_code>a = np.array([1,2,4,5,8,78,23,3])
print(np.argmax(a), np.argmin(a))
a=np.array([[1,2,4,7],[9,88,6,45],[9,76,3,4]])
print(np.argmax(a, axis=1), np.argmin(a, axis=0))<jupyter_output>[3 1 1] [0 0 2 2]<jupyter_text>---  9. Boolean & Fancy index  boolean index- numpy는 배열은 특정 조건에 따른 값을 배열 형태로 추출할 수 있음- Comparison operation 함수들도 모두 사용가능- 앞서 다뤘던 where은 index를 출력하는 것이었다면, boolean index는 boolean을 통해서 index를 알아내어 원래의 값을 추출할 때 사용<jupyter_code>test_array = np.array([1, 4, 0, 2, 3, 8, 9, 7], float)
print(test_array > 3)
print(test_array[test_array > 3])
condition = test_array < 3 
print(test_array[condition])
A = np.array([
[12, 13, 14, 12, 16, 14, 11, 10,  9],
[11, 14, 12, 15, 15, 16, 10, 12, 11],
[10, 12, 12, 15, 14, 16, 10, 12, 12],
[ 9, 11, 16, 15, 14, 16, 15, 12, 10],
[12, 11, 16, 14, 10, 12, 16, 12, 13],
[10, 15, 16, 14, 14, 14, 16, 15, 12],
[13, 17, 14, 10, 14, 11, 14, 15, 10],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
[10, 19, 12, 14, 11, 12, 14, 18, 10],
[14, 22, 17, 19, 16, 17, 18, 17, 13],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
[10, 19, 12, 14, 11, 12, 14, 18, 10],
[14, 22, 12, 14, 11, 12, 14, 17, 13],
[10, 16, 12, 14, 11, 12, 14, 18, 11]])
B = A < 15
print(B.astype(np.int)) # B에 따라 True는 1, False는 0<jupyter_output>[[1 1 1 1 0 1 1 1 1]
 [1 1 1 0 0 0 1 1 1]
 [1 1 1 0 1 0 1 1 1]
 [1 1 0 0 1 0 0 1 1]
 [1 1 0 1 1 1 0 1 1]
 [1 0 0 1 1 1 0 0 1]
 [1 0 1 1 1 1 1 0 1]
 [1 0 1 1 1 1 1 0 1]
 [1 0 1 1 1 1 1 0 1]
 [1 0 0 0 0 0 0 0 1]
 [1 0 1 1 1 1 1 0 1]
 [1 0 1 1 1 1 1 0 1]
 [1 0 1 1 1 1 1 0 1]
 [1 0 1 1 1 1 1 0 1]
 [1 0 1 1 1 1 1 0 1]]<jupyter_text>위의 코드에서 astype은 기존의 array를 copy하여 새로운 array로 변환할 때 사용  fancy index- numpy는 array를 index value로 사용해서 값을 추출하는 방법- Matrix 형태의 데이터도 가능- 앞서 다뤘던 boolean index를 주로 더 많이 사용- 하지만 추천시스템을 할 때는 fancy index도 많이 사용<jupyter_code>a = np.array([2, 4, 6, 8], float)
b = np.array([0, 0, 1, 3, 2, 1], int) # 반드시 integer로 선언
print(a[b]) # bracket index : b 배열의 값을 index로 하여 a의 값들을 추출함
print(a.take(b)) # take 함수 : bracket index와 같은 효과
a = np.array([[1, 4], [9, 16]], float)
b = np.array([0, 0, 1, 1, 0], int)
c = np.array([0, 1, 1, 1, 1], int)
print(a[b,c]) # b를 row index, c를 column index로 변환하여 표시함<jupyter_output>[ 1.  4. 16. 16.  4.]<jupyter_text>---  10. Numpy data i/o  loadtxt & savetxt- Text type의 데이터를 읽고, 저장하는 기능<jupyter_code>a = np.loadtxt("./populations.txt")
print(a[:10])
a_int = a.astype(int)
print(a_int[:3])
np.savetxt('int_data.csv', a_int, delimiter=",")<jupyter_output><empty_output><jupyter_text>numpy object - npy- Numpy object (pickle) 형태로 데이터를 저장하고 불러옴- Binary 파일 형태로 저장함<jupyter_code>np.save("npy_test", arr=a_int)
npy_array = np.load(file="npy_test.npy")
print(npy_array[:3])<jupyter_output>[[ 1900 30000  4000 48300]
 [ 1901 47200  6100 48200]
 [ 1902 70200  9800 41500]]
{'fraction_non_alphanumeric': 0.16653219299661126, 'fraction_numerical': 0.11241998816631704, 'mean_word_length': 4.689106487148103, 'pattern_counts': {'":': 0, '<': 175, '<?xml version=': 0, '>': 183, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 13, 'word_list_counts': {'cursed_substrings.json': 17, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '52', 'dir': 'jupyter-structured-clean-dedup', 'id': '476453', 'license': 'MIT', 'n_tokens_mistral': 11545, 'n_tokens_neox': 11401, 'n_words': 2267, 'path': 'src/lectures/4_numpy.ipynb', 'repo_name': 'dongminleeai/Python-for-ML', 'size': '18591'}