이것저것

Numpy 기본 설명 2(복습용으로 적는 설명) 본문

Python

Numpy 기본 설명 2(복습용으로 적는 설명)

곰태태 2023. 10. 31. 17:49
반응형
SMALL

arange 알아보기

 

Python은 데이터 타입이 명확하게 나눠져있지 않다.

Python은 Sequence Data Type을 가지고있다.

Sequence Data Type은 3가지가 있다.

Sequence Data Type은 순서가 있는 데이터 구조이다.

1. list

2. tuple

3. range

list와 tuple은 앞에서 실습해보았고

range를 살펴보자

a = range(100)
print(a)

# numpy
arr = np.arange(100)
print(arr)

arr1 = np.arange(5, 25, 2)  #5부터 25미만의 2씩 증가하는 range를 생성한다
print(arr1)

a의 출력물을 보면 range(0, 100)이라고 나오는데, 이는 0~99까지의 범위를 갖는다는 뜻이다. 값을 가지고 있는게 아니라 범위를 가지고 있는것이다.

numpy에도 range와 비슷한 것이 있는데 numpy는 범위가 아니라 진짜 값을 갖고있다. 출력물도 []안에 0 ~ 99까지 출력된다.

numpy에서 arnage를 이용해서 (시작 숫자, 마지막숫자(출력안함), 증가하는 수)를 입력해서 range를 생성할 수 있다.

 

ndarray를 만드는 방법을 배워보았다.

1. list를 가지고 만들기. array()를 가지고 만들기.

2. 제공된 함수를 이용해서 만들기.(zeros, ones, full, arange)

다음으로 배워 볼 것은 shape이다.  shape는 ndarray에서 차원과 요소수를 알려주는 대표적인 속성이다.


정규분포 & 균등분포

 

shape에 앞서 ndarray를 랜덤값을 기반해서 만드는 방법 2가지를 알아보겠다.

랜덤값 기반으로 만드는 방법은 5가지가 있지만 가장 많이 사용하는 2가지를 알아보겠다.

1. 정규분포(종모양, 좌우대칭) 확률밀도함수를 기반으로 난수를 추출해서 ndarray를 만든다.

2. 균등분포(균등한 모양) 기반으로 정수형난수를 추출해서 ndarray를 만든다.

 

난수를 적절히 골고루 뽑아야 좋은 데이터가 나오고 한쪽으로 치우쳐서 뽑게되면 좋지않은 데이터가 나온다. 그래서 정규분포와 균등분포를 많이 사용한다.

mean = 50   #평균
std = 2     #표준편차

arr = np.random.normal(mean, std, (10000,))    #랜던값으로 normal() 정규분포를 사용한다.(평균, 표준편차, shape)
print(arr)

import matplotlib.pyplot as plt

#특정 범위내에 요소가 몇개가 있나? 라는 값을 가지고 그래프를 그리는 것이 histogram이다
plt.hist(arr, bins=100)   #bins는 안에있는 데이터(10000개)를 100개로 쪼개서 보여준다
plt.show()

평균값은 50으로 표준편차를 2를 주었다. 그러면 48~52의 범위가 솓아있는 종모양으로 출력될것이다.

하지만 print(arr)로 작성하게되면 [51.47471964 51.97675629 50.68011704 ... 44.69602655 49.05177801 51.5017326 ]
이런 모습으로 나오게 되어서 제대로 나왔는지 확인이 불가능하다.

여기에서는 matplotlib라는 라이브러리를 사용해서 histogram을 그려주는 기능을 사용해보았다.

import 해주고 plt.hist(arr, bin=100)으로 10000개의 데이터를 100개로 쪼개서 보여주도록 설정하고 plt.show()를 통해 그래프를 출력한다.

print 보다 훨씬 시각적으로 볼 수 있다.

 

바로 균등분포도 확인해보겠다.

arr1 = np.random.randint(-100, 100, (10000,))      #rand 뒤의 int는 정수를 뽑아낸다는 뜻이다.  #-100부터 100까지의 10000개의 데이터를 뽑아낸다
print(arr1)
plt.hist(arr1, bins=100)
plt.show()

균등분포는 -100 ~ 100(동일하게 10000개의 데이터)에서 randint를 사용해서 정수를 뽑아내도록 하였다.

그래프를 보면 균등하게 출력된것을 확인 할 수 있다.

여기서 균등분포와 정규분포를 언제언제 사용하는지 알아보자면 실수를 추출할때는 정규분포, 정수를 추출할 때는 균등분포를 많이 사용한다.


shape 만들기

 

reshape 사용하기

 

ndarray를 만드는 방법중에 shape를 사용하는 방법에 대해서 알아보겠다.

shape는 중요한 특성이므로 잘 기억해야한다.

shape는 말그대로 배열의 형태를 바꿔준다.

대신에 안에 들어있는 총 개수가 달라지게되면 오류가 생긴다.

my_list = [[1, 2, 3], [4, 5, 6]]
arr = np.array(my_list)
print(arr, arr.shape)

#arr1 = arr.reshape(4, 5)    # 처음 총 개수가 6개인데 4,5는 20개여서 바꿀 수 없다(에러남)
arr1 = arr.reshape(1, 3, 2) # 1면 3행 2열로 변경해도 총 개수가 바뀌지는 않아서 가능하다

print(arr1[0, 1, 1])
arr1[0, 1, 1] = 0
print(arr1)
print(arr)

맨 처음 arr를 출력하게 되면 [[1 2 3] [4 5 6]] (2, 3) 이라고 출력이된다.

이는 2행 3열이라는 뜻이다.

그리고 shape는 해당 배열이 몇행 몇열인지 알려주는 명령어이다.

reshape는 배열의 총원소 개수만 같다면 행열을 변경할 수 있다.

주석처리한 reshape(4,5) 같은 경우는 원소의 개수가 20개로 바뀌는데 my_list는 원소의 개수가 6개이므로 오류가 날것이다.

그래서 reshape(1,3,2 같은 경우는 1면, 3행, 2열의 3차원 배열로 바뀌지만 총 원소의 개수는 6개로 동일하므로 오류가 나지않는다

쉽게 생각하려면 my_list는 2X3=6 이고 arr1은 1X3X2=6으로 원소의 개수가 6개로 동일하다고 보면된다.

간단한 내용이지만 나중에 까먹을까봐 길게 적어봤다...

 

마지막 단을 설명하자면 배열에 있는 요소는 내가 원하는 값으로 바꿀수도 있다.

첫번째 print(arr1[0,1,1])은 0번째 면의 1번째 행의 1번째열의 값을 출력하므로 4가 출력될것이다.

그리고 arr1[0,1,1] = 0은 위에 출력된 4의 값을 0으로 바꿔준다는 뜻이다.

그러므로 arr1을 출력하면 4가 0으로 바뀌어 있는 것을 확인 할 수 있을 것이다.

***중요***

지금 print(arr) 제일 마지막 줄이 중요하다.

우리는 arr1의 4를 0으로 바꾼것인데 arr를 출력해보면 arr의 4도 0으로 바뀐것을 확인할 수 있다.

이게 왜 바뀌었냐하면 reshape로 arr1을 생성하는 것은 arr1이라는 변수를 따로 생성하는 것이 아니라

arr의 내용을 그대로 가져와서 arr1이라고 형태만 바꿔서 view를 리턴하는 것이다.

그러므로 reshape한 데이터를 바꾸게 되면 원본데이터도 바뀌게 되므로 주의해야한다.


새로운 ndarray만들기( reshape(행, 열).copy() )

 

위에서 reshape를 수정하면 원본데이터가 바뀐다고했다

그러면 reshape를 하면 데이터를 고치면 안되는 건가?? 라고 생각했지만 당연히 코딩에서 절대 안됨은 없는게 맞다

방법은 생각보다 엄청 간단했다... 그냥 copy를 해주면된다...

import numpy as np

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

arr3 = arr.reshape(3,4).copy()
print(arr3)
#[[ 1  2  3  4]
# [ 5  6  7  8]
# [ 9 10 11 12]]


print(arr3[0,1]) # 2
arr3[0,1] = 0
print(arr3)
#[[ 1  0  3  4]
# [ 5  6  7  8]
# [ 9 10 11 12]]

print(arr)  # [ 1  2  3  4  5  6  7  8  9 10 11 12]

 

reshape 뒤에 .copy()를 적어주면 arr3은 복사본이 된다.

그러므로 arr3의 2를 0으로 바꿔주어도 arr3만 바뀌고 arr는 그대로인 것을 확인할 수 있다


resize 사용하기

.

reshape말고 resize를 사용하는 방법도 있다.

arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])

# 함수를 사용할때 원본을 대상으로 하는 함수가 있고
arr1 = arr.resize(3,5)
print(arr1)  # None

# 처리결과가 적용된 결과본을 리턴하는 함수가 있다
arr1 = np.resize(arr, (3,5))
print(arr1)
# [[ 1  2  3  4  5]
#  [ 6  7  8  9 10]
#  [11 12  0  0  0]]

resize역시 arr.resize로 배열을 바꾸게 되면 원본데이터를 바꾸게된다.

그러므로 12개의 요소가 있는 arr를 15개의 요소로 바꾼다고하니 None 갑이 출력되는 것이다. (못바꾼다는 뜻)

아래의 np는 reshape의 copy()처럼 복사본을 만드는 것, 즉, 새로운 배열을 만드는 것이라는 점은 비슷하지만

reshape의 경우에는 요소의 수가 다르면 에러를 일으키지만

resize의 경우에는 np로 복사본을 만들게되면 비어있는 요소부분은 0으로 모두 채워준다.

출력결과를 확인해보면 알 수 있다.

하지만 resize보다는 reshape를 많이 쓴다. 하지만 언제 어디서 쓸지 모르니 둘다 알아두는게 좋다.


ravel 사용하기

 

arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr)

# revel()은 무조건 1차원 ndarray로 만드는 함수이다
arr1 = arr.ravel()
print(arr1)   # [1 2 3 4 5 6]

ravel은 어떤 배열이던 1차원 배열로 만드는 함수이다.

arr의 같은경우 2행 3열의 배열이지만 arr.ravel() 적용한 arr1은 1행 6열로 바뀐것을 확인 할 수 있다.

ravel도 원본 배열의 view를 반환하므로 복사본이 있어한다.

복사본을 만들때는 ravel이 아닌 flatten()을 주로 사용한다.

flatten은 뒤에 Regression 부분에서 다시 알아보겠다.

 

오늘은 여기까지...

반응형
LIST
Comments