IT

[코딩온] 신재생에너지 IoT 개발자 입문_ 데이터분석 2

혈중당부족 2026. 2. 11. 18:04

 

2-1 넘파일 배열 연산

 

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)
print(a1 + a2)
print(a1 - a2)

3, 4번째가 a1+ a2 / a1- a2 값

 

+,-,*,/ 와 같은 산술 연산자를 바로 사용할 수 있다.

 

# 배열과 스칼라 연산(1차원)
a1 = np.array([1,2,3,4])
print(a1 + 10)
print(a1 * 2)
 
[11 12 13 14]
[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)
print(a1 + 5)
print(a2 * 3)
print(a2 / 2)

배열과 단일 값(스칼라)의 연산 시 요소별로 단일 값 연산을 한다.

이는 스칼라가 모든 원소에 적용하는 것이라서, a2 원소에서 3씩 곱해져 3번째 결과값이 나오는 거다.

 

# 배열의 구조가 다를 경우
a1 = np.array([1,2])
a2 = np.array([1,2,3])
#print(a1 + a2) #ValueError

 

브로드캐스팅 설명

전개 예시

a1 = np.array([[1,2,3],
              [4,5,6]]) # (2,3) 배열
a2 = np.array([10,20,30]) #길이가 3인 1차원 배열 (3,)

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

#2차원 행이 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)변형 : 한줄 자리를 3줄로 바꿔야 하니까
[[10,20,30]]
#a1 과 a2 비교 > (3,1), (1,3)
[[1,1,1],[2,2,2],[3,3,3]]
[[10,20,30],[10,20,30],[10,20,30]]

print(a1+a2)
[[11 21 31]
[12 22 32]
[13 23 33]]

 

이하 배열 관련 실습

더보기
#실습
#다음 배열을 생성하고, 모든 요소에 3을 더하세요
arr = np.array([1, 2, 3, 4])
print(arr + 3)

#아래 2차원 배열에서 각요소를 -1로 곱한 새로운 배열을 만드세요
arr = np.array([[5, 10],
                [15, 20]])
arr_1 = arr * -1
print(arr_1)

#아래 두 배열의 요소별 곱셈과 나눗셈 결과를 각각 출력하세요
arr1 = np.array([2, 4, 6])
arr2 = np.array([1, 2, 3])

print(arr1 / arr2)
print(arr1 * arr2)

[4 5 6 7]

[[ -5 -10]

[-15 -20]]

 

[2. 2. 2.]

[ 2 8 18]

 

# 모든 요소 최대값을 100만들기 위해 필요한 값을 더한 결과 배열을 브로드캐스팅
arr = np.array([[95,97],[80,85]])
a1 = 100 - arr
print(a1)
print(arr + a1)

#2차원 배열에서 각 행에 다른 값을 곱하여 새로운 배열 완성(브로드캐스팅)
arr5 = np.array([[1,2,3],[4,5,6]])
# 첫 번째 행 10 곱, 두번째 행 100 곱
a2 = np.array([[10],[100]])
print(arr5 * a2)

[[ 5 3]

[20 15]]

 

[[100 100]

[100 100]]

 

[[ 10 20 30]

[400 500 600]]

 

#아래 배열에서 각 행마다 다른 스칼라 값 더하기
#1차원 배열 만들어 계산 1행 100, 2행 200, 3행 300 더하기
arr6 = np.array([[10,20],
                [30,40],
                [50,60]])
a3 = np.array([100,200,300]).reshape(3,1)

print(arr6 + a3)

[[110 120]

[230 240]

[350 360]]

 

 

2-2 통계 함수 및 집계 연산

 

np.argmin (): 배열에서 최소값이 있는 인덱스 반환

np.argmax (): 배열에서 최대값이 있는 인덱스 반환.

더보기
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 -> 가장 높은 차원 기준 - >행 기준
    행 기준 = 행을 따라 연산 = 행을 증가시키며 연산 : 열(column) 단위로 계산 (세로)
axis = 1 -> 그 다음 차원 기준 - >열 기준
    열 기준 = 열을 따라 연산 = 열을 증가시키며 연산 : 행(row) 단위로 계산 (가로)
axis = n -> n번째 차원을 기준으로 연산.

a = np.array([[1,2,3],
             [4,5,6],
             [7,8,9]])
print("행기준 합", np.sum(a, axis = 0))
print("열기준 합", np.sum(a, axis = 1))
print("행기준 평균", np.mean(a, axis = 0))
print("열기준 평균", np.mean(a, axis = 1))

 

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

 

이하 실습 예제들

더보기
#아래 배열의 전체 합계와 평균을 각각 구하세요
arr= np.array([5, 10, 15, 20])

print("합", np.sum(arr))
print("평균", np.mean(arr))

#다음 2차원 배열에서 전체 최소값과 최대값을 구하세요
arr1= np.array([[3, 7, 1],
               [9, 2, 8]])

print("최소값:",np.min(arr1))
print("최대값:",np.max(arr1))

#아래 배열에서 각 열의 합계와 각 행의 합계를 각각 구하세요
arr2= np.array([[1, 2, 3],
               [4, 5, 6],
               [7, 8, 9]])

print("행기준 합", np.sum(arr2, axis = 0)) #세로방향
print("열기준 합", np.sum(arr2, axis = 1)) #가로방향
#아래 배열에서 행별 평균과 열별 평균을 각각 구하세요

arr3= np.array([[10, 20],
               [30, 40],
               [50, 60]])
print("행기준 평균", np.mean(arr3, axis = 0))
print("열기준 평균", np.mean(arr3, axis = 1))


#1차원 배열에서 전체 표준편차를 구하고, 각 요소가 평균으로부터
# 얼마나 떨어져 있는지 편차 배열을 만드세요. (값 -평균)

arr4= np.array([2, 4, 4, 4, 5, 5, 7, 9])
print("표준편차:",np.std(arr4))
print("평균:",np.mean(arr4))
print("오차:", arr4 - np.mean(arr4))


#아래 2차원 배열에서 행 단위 누적 합과 열 단위 누적 곱을 각각 구하세요
arr5= np.array([[1, 2, 3],
               [4, 5, 6]])

print("행기준 누적 합", np.cumsum(arr5, axis = 0))
print("열기준 누적 곱", np.cumprod(arr5, axis = 1))

2-3 논리 연산과 조건 연산

데이터 분석에서도 NumPy 논리 연산자를 쓰기 때문에 헷갈리지 않도록 한다. (EDA파트에서 다시 보고 있다.

 

np.where()
조건 기반 선택 함수, Python의 삼항 연산자와 유사한 역할을 한다.

arr = np.array([10,20,30,40,50])
result = np.where(arr > 30, "hing","low")
result 의 결과
array(['low', 'low', 'low', 'hing', 'hing'], dtype='<U4')
 

 

arr = np.array([10,20,30,40,50])
조건만 넣을 경우 조건을 만족하는 원소의 인덱스를 반환
 
result = np.where(arr > 30)
print(result)
print(arr[result])

(array([3, 4]),)

[40 50]

 

# and 연산(&)
arr = np.array([10,20,30,40,50])
mask = (arr > 10) & (arr < 50)
print(mask)
T/F만 알려줌 [False True True True False]
print("&연산", arr[mask])
요소 알려줌 &연산 [20 30 40]

# or 연산(|) #shift + \
mask_or = (arr > 40) | (arr < 20)
print(mask_or)
[ True False False False True]
print("|연산",arr[mask_or])
|연산 [10 50]

#not연산(~)
mask_not = ~(arr>30)
print(arr[mask_not]) [10 20 30]

 

관련 실습 예제들

더보기
#실습

#1차원 배열 [5, 12, 18, 7, 30, 25]에서 10보다 크고 20보다 작은 값만 필터링
a1 = np.array([5, 12, 18, 7, 30, 25])
a1_p = (a1 > 10) & (a1 < 20)
print(a1[a1_p])

#배열 [10, 15, 20, 25, 30, 35]에서 15 이하이거나 30 이상인 값만 선택
a2 = np.array([10, 15, 20, 25, 30, 35])
a2_p = (a2 <= 15) | (a2 >= 30)
print(a2[a2_p])

#배열 [3, 8, 15, 6, 2, 20]에서 10 이상인 값을 모두 0으로 변경
a3 = np.array([3, 8, 15, 6, 2, 20])
a3_p = (a3 >= 10)
a3_n = np.where(a3_p, 0 ,a3)
print(a3_n)
#a3[a3 >=10] = 0

#배열 [7, 14, 21, 28, 35]에서 20 이상인 값은 "High", 나머지는 "Low"로 표시하는 새로운 배열을 생성

a4 = np.array([7, 14, 21, 28, 35])
a4_p = np.where(a4 >= 20, "hing","low")
print(a4_p)

종합 예제

더보기
#0~9 범위 배열에서 짝수 그대로 두고 홀수만 x10곱 변환하기.
a5 = np.array([0,1,2,3,4,5,6,7,8,9])
a5_p = np.where(a5 % 2 == 0 , a5, a5 *10)
print(a5_p)

#아래 2차원 배열에서 20 이상, 40이하만 값 선택
a6 = np.array([[10,25,30],
               [40,5,15],
               [20,35,50]])
a6_p = (a6 >= 20 ) & (a6 <= 40)
print(a6[a6_p])

# 배열 [1,2,3,4,5,6]에서 3배수 아닌 것만 선택
a7= np.array([1,2,3,4,5,6])
a7_p = (a7 % 3 != 0)
print(a7[a7_p])
# 랜덤 정수 (0~100) 10개 배열에서 새 배열 만들기
#50 이상 값은 그대로, 50 미만은 50으로 변경
a8 = np.random.randint(0,101,size=10)
print(a8)
print(np.where(a8 >=50, a8, 50))

#2차원 배열에서 아래와 같이 분류된 문자열 생성
a9 = np.array([[5,50,95],
               [20,75,10],
               [60,30,85]])

a9_p = np.where(a9 >= 70, "A",
                np.where(a9 >= 30, "B","C"))
print(a9_p)
2-4 행렬 곱셈
 
- 두 행렬을 곱해서 새로운 행렬을 생성하는 연산
- 첫 번째 행렬의 열수(세로)와 두번째 행렬의 행수(가로)가 같아야 곱셈이 가능함
- np.dot(),np.matmul() > 사용

 

예시

1차원 배열 간 연산 -> 내적
a = np.array([1,2,3])
b = np.array([4,5,6])
print(np.dot(a,b)) # 1*4 + 2*5 + 3*6
결과값: 32
 
같은 위치의 숫자를 곱하고 모두 더함(내적)
결과= 숫자(스칼라)

물건 구매
데이터 분석에서 벡터랑 배열
c = [1000,2000,5000,10000]
d = [10, 3, 5, 7]
print(np.dot(c,d))

결과 값: 111000

 

2차원 배열간 연산 -> 행렬 곱셈
a = np.array([[1,2,3],[4,5,6]]) #(2,3)
b = np.array([[1,2],[3,4],[5,6]]) #(3,2)
print(np.dot(a,b))

표준적인 행렬 곱셉
넘파일의 행렬곱셈

np.matmul(a,b)
Matrix Multiplication
스칼라 연산 시도시 에러
0차원은 불가함.
 
a = np.array(3)
b = np.array(4)
print(np.matmul(a,b)) #ValueError

 

# 1차원 배열간 연산 - 내적 연산
a = np.array([1,2])
b = np.array([3,4])
print(np.matmul(a,b)) # 1*3 + 2*4 <교차한 지점에만
dot과 같은 내적 연산이다.
 
 
# 2차원 배열간 연산 > 행렬 곱셈
a = np.array([[1,2,3],
              [4,5,6]]) #(2,3)
b = np.array([[1,2],
              [3,4],
              [5,6]]) #(3,2)
print(np.matmul(a,b))
# 1*1+2*3+3*5(22) / 1*2 + 2*4 + 3*6(28)
# 4
[[22 28]
[49 64]]
 
 
#2차원 * 1차원 간 연산
c = np.array([[1,2],[3,4]]) #(2,2)
d = np.array([5,6]) #(2,)

print(np.matmul(c,d)) #열과 행의 개수가 맞아야 계산 됨.
print(np.matmul(d,c)) # 바뀌면 값 달라짐. 순서 유의
[17 39]
[23 34]

 

#NumPy 행렬 곱셈 - @ (python 3.5 버전 이상)

e = np.array([[1,2,3]])
f = np.array([[1,2],
              [3,4],
              [5,6]])

print(np.matmul(e,f))
print(e @ f)

동일하게 [[22 28]] 출력

 

관련 실습

더보기
#실습
#1부터 9까지의 정수로 채워진 (3, 3) 배열 A와, 모두 2로 채워진 (3, 2) 배열 B를 만들고 곱하세요
c1 = np.arange(1,10).reshape(3,3)
c2 = np.full((3,2), 2)
print(np.matmul(c1,c2)) # c1 @ c2 해도 됨.

#4×4 단위행렬 I와, 4×4 난수 행렬 M(0~9 사이 정수) 간의 곱을 구하고, 결과와 M이 동일한지 확인하세요
i = np.eye(4, 4) #단위행렬 생성식 eye
m = np.random.randint(1,10,(4,4))
print("i와 m 값\n", np.matmul(i,m))
print(m)


#모든 값이 1인 (2, 5) 배열 X와, 5부터 14까지의 연속된 정수로 채워진 (5, 2) 배열 Y를 만들어 곱하세요
x = np.full((2,5),1)
y = np.arange(5,15).reshape(5,2)
print("x와 y 곱\n", np.matmul(x,y))

#0 이상 5 미만의 임의의 정수로 채워진 (3, 2) 배열 C와 (2, 3) 배열 D를 각각 만들어
# 곱한 결과의 shape와 값을 출력하세요
c = np.random.randint(0,5,(3,2))
d = np.random.randint(0,5,(2,3))
print(np.matmul(c,d).shape)
print(c @ d)