[Python] 데이터 사이언스 스쿨 - 3.3 배열의 연산

Updated:

데이터 사이언스 스쿨 자료를 토대로 공부한 내용입니다.

실습과정에서 필요에 따라 내용의 누락 및 추가, 수정사항이 있습니다.


3.3 배열의 연산

벡터화 연산

여기선 3.1 넘파이 배열에서 확인했던 벡터화 연산에 대해 조금 더 알아본다.

import numpy as np
# 리스트
x = list(range(1,11))
y = list(range(11,21))

z = x + y
print(z)

# 배열
x = np.arange(1, 11)
y = np.arange(11, 21)

z = x + y
print(z)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[12 14 16 18 20 22 24 26 28 30]
# 논리연산
x = np.array([1,2,3,4])
y = np.array([3,2,1,4])

print(x == y)
print(x >= y)
[False  True False  True]
[False  True  True  True]
# 모든 배열의 원소 검증
x = np.array([1,2,3,4])
y = np.array([3,2,1,4])
z = np.array([1,2,3,4])

print(np.all(x == y))
print(np.all(x == z))
print(np.any(x == z))
False
True
True
  • np.all()를 이용해서 모든 배열에 대해 원소 검증이 가능하다.

  • np.any()를 이용해서 하나라도 원소 검증이 일치하는지 여부를 확인 가능하다.

# 지수함수, 로그함수 적용
x = np.array([1,2,3,4])

print(np.exp(x))
print(np.log(x))
print(x ** 2)
[ 2.71828183  7.3890561  20.08553692 54.59815003]
[0.         0.69314718 1.09861229 1.38629436]
[ 1  4  9 16]

스칼라와 벡터/행렬의 곱셈

# 스칼라 곱셈
x = np.arange(12).reshape(3,4)

100 * x
array([[   0,  100,  200,  300],
       [ 400,  500,  600,  700],
       [ 800,  900, 1000, 1100]])
# 행렬 곱셈
x = np.arange(4).reshape(2,2) # 2 x 2
y = np.arange(2).reshape(1,2) # 1 x 2

print(x)
print("-" * 10)
print(y)
print("-" * 10)
print(y * x)
[[0 1]
 [2 3]]
----------
[[0 1]]
----------
[[0 1]
 [0 3]]
  • 위 예시는 x 행렬에 행별로 y 행렬 원소를 곱해준 결과이다(행렬로 스칼라 곱셈).

  • 일반적인 행렬 곱셈 연산을 하려면 np.dot()을 사용하거나 두 행렬을 * 대신 @로 곱해준다.

브로드캐스팅

브로드캐스팅은 행렬 연산시 크기가 작은 배열을 자동으로 확장시켜주는 기능이다.

x = np.arange(5)
y = np.ones_like(x)

# 크기가 같은 행렬 덧셈
print(x + y)

# 행렬 + 1
print(x + 1)
[1 2 3 4 5]
[1 2 3 4 5]
  • 위 에시에서 x + 1을 계산하면 자동으로 1을 x와 크기가 같은 행렬로 인식해서 연산이 이루어진다.
# 다차원에서도 적용가능
# 5 x 3 행렬
x = np.vstack([range(7)[i:i + 3] for i in range(5)])
print(x)
print("-" * 10)

# 5 x 1 행렬
y = np.arange(5)[:,np.newaxis]
print(y)
print("-" * 10)

# 자동으로 y 행렬을 확장해서 연산
print(x + y)
[[0 1 2]
 [1 2 3]
 [2 3 4]
 [3 4 5]
 [4 5 6]]
----------
[[0]
 [1]
 [2]
 [3]
 [4]]
----------
[[ 0  1  2]
 [ 2  3  4]
 [ 4  5  6]
 [ 6  7  8]
 [ 8  9 10]]
  • 다차원 배열에서도 브로드캐스팅은 똑같이 적용된다.

  • 위 예시에선 y 행렬을 x행렬의 크기로 확장해서 연산한 것을 알 수 있다.

차원 축소 연산

여러 산술 함수나 앞서 벡터화 연산에서 사용한 np.all(), np.any() 등을 이용하여 차원 축소 연산이 가능하다.

# 행별로 연산
x = np.array([1, 2, 3, 5])

# 합계
print("합계:", np.sum(x))
print("합계:", x.sum())

# 최소값, 최대값
print("최소값:", x.min())
print("최대값:", x.max())

# 최소값, 최대값 위치
print("최소값 위치:", x.argmin())
print("최대값 위치:", x.argmax())

# 평균
print("평균:", x.mean())

# 중앙값
print("중앙값:", np.median(x))
합계: 11
합계: 11
최소값: 1
최대값: 5
최소값 위치: 0
최대값 위치: 3
평균: 2.75
중앙값: 2.5
# 논리 연산 - all, any
a = np.zeros((4, 4), dtype=np.int)

print(a)
print(np.any(a != 0))
print(np.all(a == a))
[[0 0 0 0]
 [0 0 0 0]
 [0 0 0 0]
 [0 0 0 0]]
False
True
# 2차원 배열 축소 연산
x = np.arange(4).reshape(2,2)
print(x)

# 전체 원소 합계
print("전체 합계:", x.sum())

# 열 합계
print("열 합계:", x.sum(axis=0))

# 행 합계
print("행 합계:", x.sum(axis=1))
[[0 1]
 [2 3]]
전체 합계: 6
열 합계: [2 4]
행 합계: [1 5]

연습문제 3.3.1

실수로 이루어진 5 x 6 형태의 데이터 행렬을 만들고 이 데이터에 대해 다음과 같은 값을 구한다.

  1. 전체의 최댓값

  2. 각 행의 합

  3. 각 행의 최댓값

  4. 각 열의 평균

  5. 각 열의 최솟값

x = np.arange(30).reshape(5,6)

print(x)
print("1. 전체의 최댓값:", x.max())
print("2. 각 행의 합:", x.sum(1))
print("3. 각 행의 최댓값:", x.max(axis=1))
print("4. 각 열의 평균:", x.mean(0))
print("5. 각 열의 최솟값:", x.min(axis=0))
[[ 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]]
1. 전체의 최댓값: 29
2. 각 행의 합: [ 15  51  87 123 159]
3. 각 행의 최댓값: [ 5 11 17 23 29]
4. 각 열의 평균: [12. 13. 14. 15. 16. 17.]
5. 각 열의 최솟값: [0 1 2 3 4 5]

정렬

a = np.array([[4,  3,  5,  7],
              [1, 12, 11,  9],
              [2, 15,  1, 14]])

# 디폴트 값은 axis = -1로 a x b x c이면 a기준 정렬
print(np.sort(a))
print("-" * 20)

# 행 정렬
print(np.sort(a, axis=1))
print("-" * 20)

# 열 정렬
print(np.sort(a, axis=0))
print("-" * 20)

# .sort로 정렬 시 배열이 변경된 채로 저장
a.sort(axis=1)
print(a)
[[ 3  4  5  7]
 [ 1  9 11 12]
 [ 1  2 14 15]]
--------------------
[[ 3  4  5  7]
 [ 1  9 11 12]
 [ 1  2 14 15]]
--------------------
[[ 1  3  1  7]
 [ 2 12  5  9]
 [ 4 15 11 14]]
--------------------
[[ 3  4  5  7]
 [ 1  9 11 12]
 [ 1  2 14 15]]
  • np.sort()sort 속성을 이용해서 배열의 정렬이 가능하며 axis를 지정하여 정렬 기준을 설정 가능하다.

  • 단, sort 속성을 사용하면 원래 배열이 정렬된 채로 저장된다.

# 정렬시 순서만 알고 싶은 경우
a = np.array([42, 38, 12, 25])
j = np.argsort(a)

print(j) # 기존 배열에서 정렬된 형태로 나오게 하기 위한 순서
print(a[j])
[2 3 1 0]
[12 25 38 42]
  • 정렬시 순서만 알고 싶은 경우 np.argsort()를 이용한다.

  • 기존 배열에서 정렬된 형태로 출력하기 위한 인덱스 순서를 반환한다.

연습문제 3.3.2

다음 배열은 첫번째 행(row)에 학번, 두번째 행에 영어 성적, 세번째 행에 수학 성적을 적은 배열이다.

영어 성적을 기준으로 각 열(column)을 재정렬하라.

array([[  1,    2,    3,    4],
       [ 46,   99,  100,   71],
       [ 81,   59,   90,  100]])
x = np.array([[  1,    2,    3,    4],
              [ 46,   99,  100,   71],
              [ 81,   59,   90,  100]])

# 단순 열 정렬 하였음
np.sort(x, axis=0)
array([[  1,   2,   3,   4],
       [ 46,  59,  90,  71],
       [ 81,  99, 100, 100]])

Leave a comment