250804 [ Day 21 ] - NumPy (3)

TaeHyun·2025년 8월 4일

TIL

목록 보기
21/184

시작하며

새로운 한 주가 시작되었다. 주말 동안 NumPy-100이라는 레퍼지토리에 있는 문제를 풀어보았는데, 아직 수업에서 배우지 않은 내용이 더 많아서 풀 수 있는 문제는 많지 않았다. 수업 시간에는 NumPy의 기본기 정도만 다루기 때문에 다른 기능들이나 심화 과정은 따로 공부를 더 해보는 것이 좋겠다고 생각했다.
오늘은 NumPy 배열의 연산과 여러 통계 함수, 논리 연산, 조건 연산에 대해 공부했다.

배열 연산

  • 배열 간 연산 (1차원)
a1 = np.array([1,2,3])
a2 = np.array([4,5,6])

print(a1 + a2)
print(a1 - a2)
# [5 7 9]
# [-3 -3 -3]

  • 배열 간 연산 (2차원)
a1 = np.arange(1,5).reshape(2,2)
a2 = np.arange(11,15).reshape(2,2)

print(a1)
print(a2)
# [[1 2]
#  [3 4]]
# [[11 12]
#  [13 14]]

print(a1 + a2)
# [[12 14]
#  [16 18]]

print(a2 - a1)
# [[10 10]
#  [10 10]]

  • 배열과 스칼라 연산 (1차원)
a1 = np.array([1,2,3,4])

print(a1 + 10)
# [11 12 13 14]

print(a1 * 2)
# [2 4 6 8]

  • 배열과 스칼라 연산 (2차원)
a1 = np.arange(1,5).reshape(2,2)
a2 = np.arange(11,15).reshape(2,2)

print(a1)
print(a2)
# [[1 2]
#  [3 4]]
# [[11 12]
#  [13 14]]

print(a1 + 5)
# [[6 7]
#  [8 9]]

print(a2 * 3)
# [[33 36]
#  [39 42]]

print(a2 / 2)
# [[5.5 6. ]
#  [6.5 7. ]]

배열의 구조가 다른 경우 에러 발생

a1 = np.array([1,2,3])
a2 = np.array([1,2])

print(a1 + a2)
# ValueError: operands could not be broadcast together with shapes (3,) (2,) 

브로드캐스팅

  • 자동으로 배열의 크기를 확장하여 서로 다른 크기의 배열 간 연산을 가능하게 하는 기능
    • 두 배열의 차원을 뒤(낮은 차원)에서부터 비교
    • 크기가 같거나 한쪽이 1인 경우 확장이 가능
a1 = np.array([[1,2,3],[4,5,6]]) # (2, 3)
a2 = np.array([10,20,30]) # (3, )

# 1차원 (3, )
[10,20,30]

# 2차원으로 변혈 (1,3)
[[10,20,30]]

# 2차원의 행이 2로 확장
[[10,20,30], [10,20,30]]

print(a1 + a2)
# [[11 22 33]
#  [14 25 36]]
a1 = np.array([[1], [2], [3]]) # (3, 1)
a2 = np.array([10,20,30]) # (3, )

# a2 : (3, ) -> (1, 3)으로 변형
[[10, 20, 30]]

# a1과 a2비교 : a1 = (3, 1), a2 = (1, 3)
# 2차원의 경우 : 3 vs 1 -> a2의 2차원이 3으로 확장
[[10, 20, 30], [10, 20, 30], [10, 20, 30]]

# 1차원의 경우 : 1 vs 3 -> a1의 1차원이 3으로 확장
[[1, 1, 1], [2, 2, 2], [3, 3, 3]]

print(a1 + a2) 

브로드캐스팅이 불가능한 경우

a1 = np.ones((2,3))
a2 = np.ones((3,2))

print(a1 + a2)
# ValueError: operands could not be broadcast together with shapes (2,3) (3,2) 

통계 함수 및 집계 연산

기본 통계 함수

  • sum( ) : 원소의 합
  • mean( ) : 원소의 평균
  • std( ) : 표준편차
  • max( ) : 최대값
  • min( ) : 최소값
  • argmax( ) : 최대값의 인덱스
  • argmin( ) : 최소값의 인덱스
  • 예시
    a = np.array([[1,2,3],[4,5,6]])
    
    print("원소의 합 :", np.sum(a))
    print("원소의 평균 :", np.mean(a))
    print("표준편차 :", np.std(a))
    print("최대값 :", np.max(a))
    print("최소값 :", np.min(a))
    print("최대값의 인덱스 :", np.argmax(a))
    print("최소값의 인덱스 :", np.argmin(a))
    # 원소의 합 : 21
    # 원소의 평균 : 3.5
    # 표준편차 : 1.707825127659933
    # 최대값 : 6
    # 최소값 : 1
    # 최대값의 인덱스 : 5
    # 최대값의 인덱스 : 0

축 (axis) 단위 연산

  • axis=0 : 가장 높은 차원 기준 → 행기준
    • 행기준 = 행을 따라 연산 = 행을 증가시키며 연산
  • axis=1 : 그 다음 차원 기준 → 열기준
    • 열기준 = 열을 따라 연산 = 열을 증가시키며 연산
a = np.array([[1,2,3],
             [4,5,6]])
print("행기준", np.sum(a, axis=0))
print("열기준", np.sum(a, axis=1))
# 행기준 [5 7 9]
# 열기준 [ 6 15]
print("행기준 평균", np.mean(a, axis=0))
print("열기준 평균", np.mean(a, axis=1))
# 행기준 평균 [2.5 3.5 4.5]
# 열기준 평균 [2. 5.]

누적 연산

  • cumsum( ) : 누적 합
  • cumprod( ) : 누적 곱
arr = np.array([1,2,3,4])
print(np.cumsum(arr)) # 누적 합
# [ 1  3  6 10]
print(np.cumprod(arr)) # 누적 곱
# [ 1  2  6 24]

논리 연산과 조건 연산

조건 연산

  • np.where( ) : 조건 기반 선택 함수
arr = np.array([10,20,30,40,50])
result = np.where(arr > 30, "high", "low")
print(result)
# ['low' 'low' 'low' 'high' 'high']

  • 조건만 넣을 경우 조건을 만족하는 원소의 인덱스를 반환
arr = np.array([10,20,30,40,50])
result = np.where(arr > 30)
print(result)
# (array([3, 4]),)
print(arr[result]) # 원본 배열에 Fancy indexing
# [40 50]

  • np.where( ) 함수를 중첩으로 사용 가능
arr = np.array([[5,50,95], [20,75,10], [60,30,85]])
result = np.where(arr >= 70, "A", np.where(arr >= 30, "B", "C"))
print(result)
# [['C' 'B' 'A']
#  ['C' 'A' 'C']
#  ['B' 'B' 'A']]

논리 연산

  • and 연산 ( & ) : 모든 조건이 True면 True
arr = np.array([10,20,30,40,50])
mask = (arr > 10) & (arr < 50)
print(arr[mask])
# [20 30 40]

  • or 연산 ( | ) : 조건 중 하나라도 True면 True
mask_or = (arr < 20) | (arr > 40)
print(arr[mask_or])
# [10 50]

  • not 연산 ( ~ ) : True는 False로, False는 True
mask_not = ~(arr > 30)
print(arr[mask_not])
# [10 20 30]

마치며

연산 파트는 지금까지 배운 내용들과 비슷해서 무난하게 따라갈 수 있었다. 하지만 axis를 사용하는 축 단위 연산에서 좀 막혔다. axis=0과 1의 개념은 이해했다고 생각했는데, 막상 문제를 풀 때는 계속 헷갈렸다. 어떤 연산을 써야 할지 충분히 생각하고 답을 작성했는데, 확인해보니 모든 문제를 반대로 작성했었다. 처음엔 당황스러웠지만 문제를 다시 천천히 읽어보면서 내가 어디서 헷갈렸는지 파악할 수 있었다. 이제 axis 문제에 어떤 식으로 접근해야 할지 감을 잡은 것 같아서 다음번엔 실수하지 않을 것 같다.

profile
Hello I'm TaeHyunAn, Currently Studying Data Analysis

0개의 댓글