SKN/04. Data Analysis

01. numpy overview

claovy☘️ 2025. 2. 28. 09:04

1. 배열 및 인덱싱

01. ndarray 생성

(1) 리스트로부터 생성

# 리스트로부터 생성
import numpy as np
arr = np.array([1, 2, 3, 4])
print(arr)

 

(2) n으로 채운 배열

# 0으로 채운 배열 생성
arr = np.zeros((2, 3))  # 2x3 배열
print(arr)

# 1로 채운 배열 생성
arr = np.ones((3, 2))  # 3x2 배열
print(arr)

 

(3) 수열을 가진 배열

# 연속적인 값으로 배열 생성
arr = np.arange(0, 10, 2)  # 0부터 9까지 2씩 증가하는 값
print(arr)

# 등간격으로 배열 생성
arr = np.linspace(0, 1, 5)  # 0에서 1까지 5개의 등간격 값
print(arr)

# 지수 | 로그로 배열 생성
arr = np.logspace(1, 3, 4) # a의 1제곱이 10, a의 3제곱이 1000이므로, base를 주지 않으면 default 값이 10 이라는 것을 알 수 있다.(기본적인 상용로그값)
print(arr)
[참고] 지수 | 로그    
- 지수 : 거듭제곱 $a^x=b$에서 x   
- 밑 : 거듭제곱될 수 $a^x=b$에서 a   
- 로그 : 밑과 거듭제곱 결과로부터 지수를 반환 $log_a{b} = x$   
- 자연로그 : 밑이 자연상수e (2.718...)인 로그   
- 상용로그 : 밑이 10인 로그

 

(4) 정규분포를 따른 배열

# 정규분포로 난수 배열 생성
arr = np.random.randn(2, 3)  # 2x3 배열
print(arr)

 

02. ndarray 형변환

형변환 
# 형변환
arr = np.array([1.234, 5.678, 9, 10]) # 묵시적 형 변환
arr = np.array([1.234, 5.678, 9, 10], dtype = float) # 명시적 형 변환
arr = np.array([1.234, 5.678, 9, 10], dtype = int) # float -> int 형 변환은 소숫점은 그대로 버림 
arr, arr.dtype 

arr = np.array([1.234, 5.678, 9, 10])
arr = arr.astype(int) # astype : 자료형 변환

arr, arr.dtype

[출력]
(array([ 1,  5,  9, 10]), dtype('int64'))

 

03. ndarray 인덱싱

(1) slicing은 차원을 유지해준다

print(arr[:-1, 0:1], arr[:-1, 0:1].shape) # 슬라이싱 = 차원 유지 
print(arr[:-1, 0], arr[:-1, 0].shape) # 인덱스로 접근하면 값을 꺼내서 반환하기 때문에 차원이 제거된다.

[출력]
[[10]
 [40]] (2, 1) 
[10 40] (2,)

 

(2) fancy indexing

1차원 배열 fanct indexing
arr = np.arange(5,31,5)
print(arr)
print(arr[[1, 3, 5]])

indices = [1, 3, 5]
print(arr[indices])

[출력]
[ 5 10 15 20 25 30]
[10 20 30]
[10 20 30]
2차원 배열 fancy indexing
arr = np.array([
    [5, 10, 15, 20],
    [25, 30, 35, 40],
    [45, 50, 55, 60]
])

# 찾고 싶은 인덱스 = [10 35]
indices1 = [0,1]
indices2 = [1,2]

print(arr[indices1,indices2])
print(arr[[0,1],[1,2]])

[출력]
[10 35]
[10 35]

 

(3) boolean indexing

1차원 배열 boolean indexing
arr = np.arange(1,6)
print(arr)

bools = [True, False, False, False, True]
print(arr[bools])

[출력]
[1 2 3 4 5]
[1 5]
2차원 배열 boolean indexing
arr = np.array([
    [3, 6, 9],
    [12, 15, 18],
    [21, 24, 27]
])

print(arr[arr > 10])
print(arr[arr % 2 == 0])

[출력] # 조건에 맞는 배열을 출력할 수 있다
[12 15 18 21 24 27]
[ 6 12 18 24]

 

(4) 조건 반환

np.all() : ndarray의 모든 요소가 조건을 만족할 때 True 반환
arr = np.array([10, 20, 30, 40, -50])

is_all_positive = np.all(arr>0)

if is_all_positive:
    print('모든 수는 양수입니다')
else:
    print('모든 수가 양수는 아닙니다.')
    
[출력]
모든 수가 양수는 아닙니다
np.any() : ndarray의 요소가 조건을 하나라도 만족할 때 True 반환
arr = np.array([10, 20, 30, 40, -50])

has_positive = np.any(arr>0)

if has_positive:
    print('양수가 포함되어 있습니다다')
else:
    print('모든 수가 양수입니다.')
    
[출력]
양수가 포함되어 있습니다

2. numpy 연산

01. Dot Product 연산

💡점곱연산 (Dot Product / 내적)   
- 두 행렬 A, B의 곱셈은 첫 번째 행렬 A의 행과 두 번째 행렬 B열 간의 곱셈을 수행한다.    
- 첫 번째 행렬 A의 열의 수와 두 번째 행렬 B의 행의 수가 같아야 한다.   
- 연산 결과의 shape은 (첫 번째 행렬 A의 행수, 두 번째 행렬 B의 열수) 이다.
arr3 = np.array([[1, 2, 3],[4, 5, 6]]) #(2,3)
arr4 = np.array([[7, 8],[9, 10],[11, 12]]) #(3,2)
arr3.shape, arr4.shape # arr3과 arr4가 내적되었을 떄 shape을 상상해보자. arr3의 행, arr4의 열이 나올 것이다

print(np.dot(arr3,arr4).shape)
print(np.dot(arr4,arr3).shape) 

[출력]
(2, 2)
(3, 3)
[[ 7  8]
 [ 9 10]
 [11 12]]
[[1 2 3]
 [4 5 6]]


🤔 만약 배열의 순서를 바꾼다면?
# print(arr4) # (3, 2) 
# print(arr3) # (2, 3)  이렇게 되니까 arr4의 행, arr3의 열을 따와서 둘의 내적은 (3, 3) 이 된다.

 

02. broadcasting 연산

arr_a = np.arange(1,10).reshape(3,3)

result_arr = arr_a * np.array([[5, 5, 5],[5, 5, 5],[5, 5, 5]]) # (3, 3)
result_arr = arr_a * np.array([5, 5, 5]) # (3, )
result_arr = arr_a * np.array([5]) # (1, )
result_arr = arr_a * 5 # 스칼라값 
result_arr

[출력]
array([[ 5, 10, 15],
       [20, 25, 30],
       [35, 40, 45]])

3,3 배열인 arr_a과 같은 요소값을 가진 여러 배열들을 곱한 결과 모두 같은 값이 출력된다.

이는 numpy의 broadcating 연산 때문이다.

⭐ 2차원과 1차원의 연산을 고려해보자
- 두 배열이 shape이 다르면 broadcating 연산을 수행한다
- shape이 작은 쪽에서 큰 쪽에 맞춰 확장한다
- 두 배열의 행 또는 열이 일치해야 확장 가능하다
- 크기가 1인 경우 무조건 확장 가능하다
- shape이 다른 경우 마지막 축부터 차원이 동일한지 비교한다
- 1차원이 자신보다 큰 차원을 만나면 요소의 개수를 맞춰주기 위해 확장된다!!!! (작은쪽에서 큰 쪽으로 확장)
arr1 = np.array([[1, 2, 3], [4, 5, 6]]) # (2, 3)
arr2 = np.array([5, 10, 15]) # (3, )

print(arr1) 
print(arr2)
arr1 + arr2

[출력]
[[1 2 3]
 [4 5 6]] # arr1 
[ 5 10 15] # arr2
array([[ 6, 12, 18], # arr1 + arr2
       [ 9, 15, 21]])

1차원인 arr2는 arr1에 맞춰 확장된다.

이렇게 배열은 작은 차원에서 큰 차원으로 수를 확장시킨다.

 

한 예시를 더 보자

arr1 = np.array([1, 2, 3]) # (3,)
arr2 = np.array([[4], [5], [6]]) # (3,1)
arr1.shape, arr2.shape

print(arr1)
print(arr2)
arr1 + arr2

[출력]
[1 2 3] #arr1
[[4] #arr2
 [5] #arr2
 [6]] #arr2


array([[5, 6, 7],
       [6, 7, 8],
       [7, 8, 9]])  # arr1 + arr2

 요소가 적은 arr2가 arr1을 맞춰 np.array([[4, 4, 4], [5, 5, 5], [6, 6, 6]]) 형태로 확장한 구조이다. 

 

<!-------------- 에러코드!!!!!!!!!!!!!!!! ---------------!>


arr1 = np.array([[1, 2, 3],[1, 2, 3]]) # (2, 3)
arr2 = np.array([1, 2]) # (2, )

그러나, 행과 열이 일치하지 않을 경우 arr2가 [1,2], [1,2]로 확장이 되더라도 요소가 없어서 확장하지 못한다. 

 

03. 집계함수

올림 반올림 (ceil, round)
arr_float = np.array([[1.234, 5.678],[7.89, 10.123]])
print(np.ceil(arr_float)) # 올림
print(np.round(arr_float)) # 반올림
print(np.round(arr_float, 2)) # 두 번째 인자는 소숫점을 어디까지 표시할것인지다

[출력]
[[ 2.  6.]
 [ 8. 11.]]

[[ 1.  6.]
 [ 8. 10.]]
 
[[ 1.23  5.68]
 [ 7.89 10.12]]
내림 절삭 (floor, trunc)
arr_float = np.array([[1.234, -5.678],[-7.89, 10.123]])
print(np.floor(arr_float))
print(np.trunc(arr_float))

[출력]
[[ 1. -6.]
 [-8. 10.]]
 
[[ 1. -5.]
 [-7. 10.]]

 

'SKN > 04. Data Analysis' 카테고리의 다른 글

05. matplotlib  (0) 2025.03.06
04. 데이터 결측치 확인  (0) 2025.03.06
03. pandas overview  (0) 2025.03.04
02. numpy [통계] [정렬] [병합]  (0) 2025.02.28