<jupyter_start><jupyter_text>**NumPy - Calculate**NumPy를 이용해 배열의 연산을 하는 기본적인 방법에 대해 알아보자. 면면이 파고들어가면 공부할 내용이 많은 부분이지만 여기서는 우선 기초적인 내용만을 다뤄보자!  다룰 내용1. Basic calculate2. Broadcasting3. Functions4. Performance 비교<jupyter_code>import numpy as np<jupyter_output><empty_output><jupyter_text>**1. Basic calculation**  1.1 사칙연산 먼저 간단하게 list와 numpy에서 계산이 어떻게 다른지 비교해보자. list 자료형에서는 더하기(`+`)는 2개의 리스트를 합치는 기능을 하고, 곱하기(`*`)를 사용하면 곱한 수만큼 element를 반복해서 연결한 list를 만들어낸다.<jupyter_code>ls = [1, 2, 3]
print(ls + ls)
print(ls * 3)<jupyter_output>[1, 2, 3, 1, 2, 3]
[1, 2, 3, 1, 2, 3, 1, 2, 3]<jupyter_text>반면, NumPy에서 `*`, `+`, `-` 등 연산자는 ndarray에 있는 magic method로, list와는 달리 각 element에 해당 계산을 해준다.<jupyter_code>na1 = np.array([1, 2, 3])
na1 * 3
na1 - 1
na2 = np.array([4, 5, 6])
na1 + na2<jupyter_output><empty_output><jupyter_text>NumPy에서 vector나 matrix간에 사칙연산을 하면, 같은 위치의 원소끼리 계산이 이뤄진다. 이렇게 되려면 당연하게도 계산하려는 vector나 matrix가 형태가 같아야 한다.<jupyter_code>na3 = np.arange(6).reshape(2,3)
na4 = np.arange(6, 12).reshape(2, 3)
print("array3 : \n{}".format(na3))
print("array3 : \n{}".format(na4)) 
print("multiplied : \n{}".format(na3*na4))<jupyter_output>array3 : 
[[0 1 2]
 [3 4 5]]
array3 : 
[[ 6  7  8]
 [ 9 10 11]]
multiplied : 
[[ 0  7 16]
 [27 40 55]]<jupyter_text>1.2 비교연산 NumPy에서는 다음과 같이 비교연산이 가능하다.  (1) array 내의 원소 비교연산<jupyter_code>print("na1:", na1)
print("na2:", na2)

print(na1 == 2)
print(na2 > 4)<jupyter_output>na1: [1 2 3 4 5]
na2: [1 3 3 4 4]
[False  True False False False]
[False False False False False]<jupyter_text>(2) `all`: 전체리스트 비교하기 (원소별이 아니라 array 전체의 비교 연산)<jupyter_code>na1 = np.array([1, 2, 3, 4, 5])
na2 = np.array([1, 3, 3, 4, 4])
na3 = np.array([1, 2, 3, 4, 5])

print(np.all(na1 == na2))
print(np.all(na1 == na3))<jupyter_output>False
True<jupyter_text>1.3 필터링비교연산 등을 통한 True / False 리스트를 offset으로 넣어주면 True인 데이터만 필터링할 수 있다.<jupyter_code>print("na1:", na1)
print("na2:", na2)

print(na1[na1 == 2])
print(na2[na2 > 4])
# 3의 배수만 출력하기
na3 = np.arange(10)
print(na3)
print(na3[na3 % 3 == 0])
# 두 array를 위치별로 비교하여 필터링
ls1 = np.array([1, 2, 3, 4, 5])
ls2 = np.array([0, 1, 3, 0, 5])
ls1[ls1 == ls2]<jupyter_output><empty_output><jupyter_text>**2. Broadcasting**  2.1 vector/matrix와 scalar의 사칙연산vector/matrix의 각 element에 해당 연산을 수행한다.<jupyter_code>na = np.array([1, 2, 3])
na * 2
na = np.array(range(12)).reshape(3, 4)
print("na: \n{} \n".format(na))
print("na에 + 1을 하면: \n{}".format(na + 1))<jupyter_output>na: 
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]] 

na에 + 1을 하면: 
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]<jupyter_text>2.2 matrix와 vector의 사칙연산행/열 vector를 matrix의 각 행/열에 연산한다.<jupyter_code>na1 = np.array(range(4))
print("na: \n{}\n".format(na))
print("na1: \n{}\n".format(na1))
print("na + na1: \n{}".format(na + na1))
na2 = np.array(range(3))[:, np.newaxis]  # `np.newaxis` 행/렬을 바꿔줌
print("na: \n{}\n".format(na))
print("na2: \n{}\n".format(na2))
print("na + na2: \n{}".format(na + na2))<jupyter_output>na: 
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

na2: 
[[0]
 [1]
 [2]]

na + na2: 
[[ 0  1  2  3]
 [ 5  6  7  8]
 [10 11 12 13]]<jupyter_text>**3. Function**  3.1 min, max, argmin, argmax- min, max: 최소값, 최대값- argmin, argmax: 최소값, 최대값의 위치 index<jupyter_code>na = np.random.randint(10, size=(2, 3))
na
print("최소값, 최대값: {}, {}".format(na.min(), na.max()))
print("최소값 index, 최대값 index: {}, {}".format(na.argmin(), na.argmax()))<jupyter_output>최소값 index, 최대값 index: 1, 3<jupyter_text>3.2 sum, mean, median, std, var  (1) sum<jupyter_code>na
print(np.sum(na))          # 모든 요소의 값을 더함
print(np.sum(na, axis=0))  # 컬럼끼리 더해짐 (0번째 축인 행 방향으로 더함)
print(np.sum(na, axis=1))  # 로우끼리 더해짐 (1번째 축인 열 방향으로 더함)<jupyter_output>33
[14  8 11]
[14 19]<jupyter_text>(2) mean, median<jupyter_code>print(np.mean(na))
print(np.median(na))<jupyter_output>5.5
5.0<jupyter_text>(3) std, var<jupyter_code>print(np.std(na))
print(np.var(na))<jupyter_output>1.707825127659933
2.9166666666666665<jupyter_text>3.3 all, any - 단순 비교연산: array의 각 요소끼리(같은 위치) 비교함- `all`: 하나라도 false이면 false (and 와 유사)  (값만 비교함, not 주소값)- `any`: 하나라도 true이면 true (or 와 유사)<jupyter_code>na1 = np.array([1, 2, 3])
na2 = na1
na3 = np.array([1, 0, 3])
print("na1: {}".format(na1))
print("na2: {}".format(na2))
print("na3: {}".format(na3))
# 단순 비교연산
print(na1 == na2)
print(na2 == na3)
# all
print(np.all(na1 == na2))
print(np.all(na1 == na3))
# any
print(np.any(na == na2))
print(np.any(na == na3))<jupyter_output>False
False<jupyter_text>3.4 분위수<jupyter_code># 100등분을 해야하기 때문에 1이 아니라 0부터 시작되어야 함
na = np.arange(0, 101)     
na
np.percentile(na, 25)    # 4분위수<jupyter_output><empty_output><jupyter_text>3.5 지수함수와 로그함수<jupyter_code>na = np.arange(1, 6)
na<jupyter_output><empty_output><jupyter_text>(1) 지수함수(exponential function) - scale up<jupyter_code># 밑이 e(오일러 넘버)인 지수함수
np.exp(na)<jupyter_output><empty_output><jupyter_text>(2) 로그함수(log function) - scale down<jupyter_code># 밑이 e(오일러 넘버)인 로그함수
np.log(na)
# 밑이 다른 로그함수는 다른 함수를 사용
np.log10(10), np.log2(2)<jupyter_output><empty_output><jupyter_text>**4. Performance 비교** list에 비해 numpy array의 연산 속도가 정말 더 빠른지, 10**7 까지의 리스트에서 3과 5의 배수의 개수를 찾는 연산에 걸리는 시간을 비교해보자<jupyter_code>ls = []
size = int(1E7) # (10의 7제곱)
ls = [num for num in range(size)]
len(ls)
na = np.arange(size)
len(na)
%%time
count = 0
for idx in ls:
    if (ls[idx] % 3 ==0) or (ls[idx] % 5 == 0):
        count += 1
count        
%%time
count = len(na[(na % 3 ==0) | (na % 5 ==0)])   # array를 필터링해서 요소의 개수 구함
count<jupyter_output>Wall time: 295 ms
{'fraction_non_alphanumeric': 0.1860036832412523, 'fraction_numerical': 0.07384898710865562, 'mean_word_length': 4.485858585858586, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '19', 'dir': 'jupyter-structured-clean-dedup', 'id': '559685', 'license': 'MIT', 'n_tokens_mistral': 3284, 'n_tokens_neox': 3573, 'n_words': 646, 'path': 'python_23_NumPy_calculate.ipynb', 'repo_name': 'hyeshinoh/Python_Study', 'size': '5430'}