본문 바로가기

Python/Data Analysis

Data Analysis / NumPy / ndarray(1)

< ndarray 생성 >

import numpy as np

a = [1,2,3,4,5]	# python의 list
print(a)	# [1,2,3,4,5]

# python의 list를 가지고 np array 생성 가능
arr = np.array(a)
print(arr)	# [1 2 3 4 5] => 콤마(,)가 없음에 유의!
print(type(arr))	# <class 'numpy.ndarray'>
# dtype 속성으로 데이터의 타입을 알 수 있음
print(arr.dtype)	# int32
# index번호로 접근도 가능
print(arr[0])	# 1

print(type(arr[0]))	# <class 'numpy.int32'>
b = [100, 3.14, True, 'Hello']
arr2 = np.array(b)
print(arr2)	# ['100' '3.14' 'True' 'Hello'] => 전부 문자열로 만들어짐
# 공통적으로 변환 가능한 타입이 문자열이기 때문이다.

# 다차원의 ndarray를 만드려면?
# python의 list는 중첩리스트만 존재함
a = [[1,2,3], [4,5,6]]
arr = np.array(a)
print(arr)
# [[1 2 3]
# [4 5 6]]
# 2차원 배열의 indexing
print(arr[1,1])	# 5

# NumPy가 제공해주는 데이터 타입을 이용해서 만들 수도 있다.
arr = np.array(a, dtype=np.float64)
print(arr)	# 소수점이 나오는 걸로 보아 float 형임을 알 수 있다.
# [[1. 2. 3.]
# [4. 5. 6.]]

< ndarray의 속성과 크기 >

# ndarray의 차원 관련 속성
import numpy as np

a = [1,2,3,4]
arr = np.array(a, dtype=np.float64)

print(arr.ndim)	# ndim => 차원의 개수 : 1
print(arr.shape)	# 각 차원의 요소수를 tuple로 표현 => (4, )

a = [[1,2,3], [4,5,6], [7,8,9], [10,11,12]]
arr = np.array(a, dtype=np.float64)
print(arr.shape)	# (4, 3)

## 3차원 중첩리스트를 만들어보자
# ndarray를 생성한 후 shape가 (2,2,3)으로 나오도록 만들어보자
a = [ [ [1,2,3], [1,2,3] ], [ [1,2,3],  [1,2,3] ] ]
arr = np.array(a, dtype=np.float64)
print(arr.shape)	# (2,2,3)

# numpy array(ndarray)의 크기
a = [[1,2,3],[4,5,6],[7,8,9],[10,11,12]] # 4 x 3
arr = np.array(a, dtype=np.float64) # 4 x 3
print(arr.size)	# 총 데이터의 수 : 12
print(len(arr))	# 첫 번째 차원의 요소 개수를 리턴 : 4

# 직접 shape를 바꾸어 줄 수도 있음
arr.shape = (2, 6)	# 데이터는 그대로 두고 모양만 바꿈
print(arr)
# [[ 1.  2.  3.  4.  5.  6.]
# [ 7.  8.  9. 10. 11. 12.]]

# 차원이 달라져도 size만 같으면 됨
arr.shape = (3,2,2)
print(arr)
# [[[ 1.  2.]
#  [ 3.  4.]]

# [[ 5.  6.]
#  [ 7.  8.]]

# [[ 9. 10.]
#  [11. 12.]]]

# 만약 원래 data와 size가 다르게 조절하면 에러!!
# arr.shape = (3,2,3)
# print(arr)	# error : size가 서로 다름

# ndarray의 data type을 변경하려면?
arr = np.array([1.5, 2.3, 8.3, 9.8, 7.7], dtype=np.float64)

# astype() 함수를 이용해서 매개변수로 전달한 타입으로 변경
result = arr.astype(np.int32)
# 실수형을 정수형으로 바꾸면 버림처리 된다!!
print(result)	# [1 2 8 9 7]
print(result.dtype)	# int32

< ndarray를 만드는 여러가지 방법 >

## ndarray를 만드는 여러가지 방법

import numpy as np

arr = np.zeros((3,4))	# 0으로 채운 numpy array를 만듬 (매개변수로 shape 전달)
# default dtype은 np.float64
print(arr)
# [[0. 0. 0. 0.]
# [0. 0. 0. 0.]
# [0. 0. 0. 0.]]

arr = np.ones((2,5))	# 1로 채운 numpy array 생성
print(arr)
# [[1. 1. 1. 1. 1.]
# [1. 1. 1. 1. 1.]]

# full() : 주어진 값과 dtype으로 shape만큼 array를 채워서 만듬
arr = np.full((3,5), 7, dtype=np.float64)
print(arr)
# [[7. 7. 7. 7. 7.]
# [7. 7. 7. 7. 7.]
# [7. 7. 7. 7. 7.]]

arr = np.empty((3,3))	# 3 x 3 ndarray를 생성하는데 초기값을 주지 않음
# 내가 원하는 shape 만큼의 공간만 설정 (쓰레기 값이 들어감)
print(arr)
# [[0.00000000e+000 0.00000000e+000 0.00000000e+000]
# [0.00000000e+000 0.00000000e+000 4.64421707e-321]
# [6.18050016e+223 9.30684533e+242 4.39204058e+199]]

# 만들어져 있는 numpy array를 인자로 전달
result = np.zeros_like(arr, dtype=np.float64)
# 전달된 array의 shape 크기대로 만듬 (0으로 채움)
print(result)
# [[0. 0. 0.]
# [0. 0. 0.]]

# arange : python의 range와 상당히 유사
# 주어진 범위 내에서 지정한 간격으로 연속적인 원소를 가진 ndarray 생성
a = range(1, 10, 1)
print(a)	# range(1, 10)

arr = np.arange(1, 10, 1)	# 실제 numpy array가 만들어짐
print(arr)	# [1 2 3 4 5 6 7 8 9]

# linspace 기능으로 ndarray 생성 가능
# linspace 기능을 확인하기 위해서 그래프 데이터를 그려보자
# matplotlib module : 그래프를 그리기 위한 모듈

import numpy as np
import matplotlib.pyplot as plt

# np.linspace(start, stop, num)
# start부터 시작해서 stop의 범위에서 (start와 strop 모두 범위에 포함)
# num개의 숫자를 균일한 간격으로 데이터를 생성해서 ndarray를 만드는 함수

arr = np.linspace(0, 10, 11)
print(arr)	# [ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9. 10.]

arr = np.linspace(1, 121, 31)
print(arr)
# [  1.   5.   9.  13.  17.  21.  25.  29.  33.  37.  41.  45.  49.  53.
#  57.  61.  65.  69.  73.  77.  81.  85.  89.  93.  97. 101. 105. 109.
# 113. 117. 121.]

# 원소간의 간격 : (stop-start) / (num-1)
# 120 / 30 => 4
# [1 5 9 ... ]

plt.plot(arr, "*")	# * 모양을 점으로 찍는 그래프 생성
plt.show()	# 그래프를 출력

< 랜덤 값을 기반으로 ndarray 생성 >

# 랜덤 값을 기반으로 ndarray 생성하는 5가지 방법
# 1. np.random.normal() : 정규분포 확률밀도함수에서 실수 표본을 추출
# 평균과 표준편차를 지정해주어야 한다.
mean = 50	# 평균
std = 2		# 표준편차
arr = np.random.normal(mean, std, (100000, ))
print(arr)
# matplotlib의 hist() 함수를 이용해서 히스토그램을 그릴 수 있다.
# bins : 몇개의 영역으로 나눌지 지정
plt.hist(arr, bins=100)
plt.show()

# 2. np.random.rand : 실수를 추출하는데 [0, 1) 범위에서 균등분포로 추출
# rand(d0, d1, d2, ... )로 각 차수별 개수 지정
arr = np.random.rand(100000)
print(arr)

# 3. np.random.randn(d0, d1, d2, ...) : 실수추출, 표준정규분포에서 난수 추출
# 표준정규분포 : 평균이 0, 표준편차가 1
arr = np.random.randn(100000)
print(arr)

# 4. np.random.randint(low, high, shape) : 정수추출, 균등분포 확률밀도함수에서 난수추출
arr = np.random.randint(-100, 100, (100000, ))
print(arr)

# 5(잘안씀). np.random.random(shape) : [0, 1) 균등분포에서 실수 난수 추출
arr = np.random.random((100000, ))
print(arr)

< NumPy가 제공하는 랜덤 관련 함수 >

# NumPy가 제공하는 랜덤 관련 함수
import numpy as np

# 1. 난수의 재현
# 정수형 난수 생성은 randint를 사용하는 것이 유일
# 랜덤값도 실제로는 특정 알고리즘의 결과물
# 초기에 시작값(seed)을 설정해주면 항상 같은 랜덤값이 도출됨
np.random.seed(10)
arr = np.random.randint(0, 100 , (10, ))
print(arr)	# [9 15 64 28 89 93 29 8 73 0]

# 2. ndarray의 순서를 랜덤하게 바꾸려면? - shuffle
arr = np.arange(10)
print(arr)	# [0 1 2 3 4 5 6 7 8 9]
np.random.shuffle(arr)	# ndarray 자체가 변경됨!! (return 되는 것이 아님)
print(arr)	# [7 0 9 2 4 1 3 8 5 6]

# 3. ndarray 안에서 일부를 무작위로 선택하는 기능 - sampling
# sampling 기능을 수행하려면 choice() 함수를 이용
# np.random.choice(arr, size, replace, p)
# arr : numpy array 또는 정수
# 만약 정수면, arange(정수)로 numpy array를 생성하여 이에 대해 수행
# size : 정수값, 샘플의 수
# replace : boolean(True, False)
# True : 한 번 선택한 데이터를 다시 샘플링에 사용 가능
# False : 한 번 선택한 데이터를 다시 샘플링에 사용 불가
# p : ndarray. 각 데이터가 샘플링 될 확률을 가지고 있는 ndarray

arr = np.random.choice(5, 10, replace=True, p=[0.2,0,0.3,0.4,0.1])
# [0,1,2,3,4]을 입력으로 주는 것과 같음
print(arr)	# [4 2 0 2 3 2 0 3 2 3]

< reshape() 와 ravel() 함수 >

# shape 속성의 값을 직접 바꾸어서 ndarray의 형태를 변경하는 것은 좋지 않음
# reshape() 함수를 이용해서 처리하는 것이 바람직하다.
improt numpy as np

arr = np.arange(0,12,1)

arr1 = arr.reshape(4,3)	# 새로운 ndarray를 만드는 것이 아니라 view를 생성
# view : 모양만 바뀐 창문의 역할
print(arr)	# [ 0 1 2 3 4 5 6 7 8 9 10 11]
print(arr1)
# [[ 0  1  2]
# [ 3  4  5]
# [ 6  7  8]
# [ 9 10 11]]

arr[0] = 100
print(arr1)	# 같은 데이터를 공유하고 있으므로 arr1도 바뀐다.
# [[100   1   2]
# [  3   4   5]
# [  6   7   8]
# [  9  10  11]]

arr[0] = 0
# -1을 인자로 주면 알아서 계산하라는 뜻이다.
arr1 = arr.reshape(2, -1)	# (2,6)
arr2 = arr.reshape(-1, 4)	# (3,4)
arr3 = arr.reshape(2,2,-1)	# (2,2,3)

# copy() 함수를 사용하여 view가 아니라 실제 ndarray를 생성 가능
arr1 = arr.reshape(2,6).copy()
print(arr1)
# [[ 0  1  2  3  4  5]
# [ 6  7  8  9 10 11]]

# ravel() : ndarray의 모든 요소가 포함된 1차원 vector를 return
# ravel() 함수도 view를 return
arr = np.arange(0,12,1).reshape(2,-1).copy()
arr1 = arr.ravel()
print(arr1)	# [ 0 1 2 3 4 5 6 7 8 9 10 11]