클래스나 함수 선언을 보면 자주 input으로 array_like형 데이터 타입을 요구하는 경우가 많다. 그러나 array_like라고 하면 이해하기 힘든 경우가 많아 한번 정리하려고 한다.

 

Numpy의 공식 홈페이지에서는 다음과 같이 설명되어 있다.

 

array_like는 array로 해석될 수 있는 모든 scalar또는 sequence이다. 또한 여기에는 list(중첩과 다른 요소 유형을 포함하는)와 tuple 또한 포함된다.

 

일반적으로 파이썬에서 array_like 구조로 배열된 수치 데이터는 np.array()함수를 사용하여 array로 변환이 가능하다. 예시로는 tuple과 list가 있다. 따라서 가장 간단하게 array_like인지 확인 가능한 방법이다.

 

그러나 이러한 방법은 array_like가 무엇인지에 대한 확실한 정답을 내려주지는 않는다. 이는 array_like라는 단어가 입력이 무엇이 들어와야 하는지 정의하는 것이 아닌 입력을 설명하는 것에 가깝기 때문이다.

 

이는 Numpy에서 유연하게 데이터를 얻기 위해 이러한 형태로 만들었을 것이라 생각한다.

 

https://stackoverflow.com/questions/40378427/numpy-formal-definition-of-array-like-objects

 

numpy: formal definition of "array_like" objects?

In numpy, the constructors of many objects accept an "array_like" as first argument. Is there a definition of a such object, either as an abstract meta class, or documentation of the methods is sho...

stackoverflow.com

다음과 같은 stack overflow에서 소스코드를 분석하여 array_like가 무엇인지 확인하였다.

 

결과를 확인한다면 다음과 같은 input을 array_like라고 정의한다.

위와 같이 다양한 방법으로 처리되며 일일히 확인이 불가능하여 일반적으로 배열과 유사한 것은 모두 가능하다고 적어놓은 것 같다.

 

iterable은 파이썬 표준 용어로써 반복될 수 있는 모든 것을 나타낸다.

간단한 예를 들어 우리는 문자열을 변수에 넣어주면 이는 for 문을 통해 나올 수 있다.

 

여기서 한 가지 주의해야 할 점은 'array_like에 속해있는 대부분의 데이터 타입은 iterable 데이터 타입이니 iterable 데이터 타입이 array_like과 같나?'라는 생각을 할 수 있다. 

 

간단한 예를 들어 반박 가능한데 스칼라 값은 array_like에 속해있지만 iterable한 데이터 타입이 아니다.

즉 a = 3은 np.array(a)에서 오류가 나오지 않지만 for문을 통해 돌리면 에러가 나온다.

 

또한 iterable 데이터 타입은 np.array를 통해서 Numpy array으로 만들수 없다.

iterable = (x*x for x in range(5))

iterable

#결과
<generator object <genexpr> at 0x7f6fafed06d0>

np.array(iterable)

#결과
array(<generator object <genexpr> at 0x7f6fafa93f50>, dtype=object)

np.fromiter(iterable, float)

#결과
array([ 0.,  1.,  4.,  9., 16.])

다음의 결과를 보면 generator object인 iterable을 만들었다. 이를 np.array에 삽입하였으며 결과를 확인해 보면 object형태로 들어갔으며 배열을 형태가 나오지 않은 것을 볼 수 있다. 따라서 iterable 형태가 array_like이 아닌것을 확인 가능하다. 이러한 문제는 np.fromiter를 이용하여 해결 가능하다. 

 

 

'Python > numpy' 카테고리의 다른 글

난수 생성 - numpy .random.permutation  (0) 2022.03.09
난수 생성 - np.random.seed, np.random.RandomState  (0) 2022.03.08

numpy.random.permutation(x)

시퀀스를 무작위로 치환하거나 치환된 범위를 반환해 주는 함수이다.

 

Parameter 

  • x : int or array_like

Returns

  • out : ndarray

input인 x는 2가지가 들어갈 수 있다.

 

첫 번째는 int가 들어갈 수 있다. 함수는 이를 범위로 인식하고 범위에 해당하는 정수형 ndarray배열을 무작위로 섞어서 반환한다.

 

다음은 10을 넣었을 때의 예제이다.

import numpy as np

per = np.random.permutation(10)

#결과
array([8, 7, 4, 3, 2, 9, 0, 1, 5, 6])

 

두 번째 input으로는 array_like가 들어갈 수 있다. 이는 array_like의 원소를 랜덤 하게 섞어서 ndarray의 형태로 반환하여 준다.

 

다음은 리스트를 넣었을 때의 예제이다.

per = np.random.permutation([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

#결과
array([3, 1, 6, 5, 7, 8, 9, 0, 4, 2])

 

또한 x는 다차원 배열이 들어갈 수도 있다. 그러나 이렇게 되면 가장 처음에 있는 차원을 기준으로만 섞이게 된다.

 

다음은 3x3 배열과 3x3x3배열의 예제이다.

arr1 = np.arange(9).reshape((3,3))
arr2 = np.arange(27).reshape((3,3,3))

arr1

#결과
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
       
arr2

#결과
array([[[ 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]]])
        
np.random.permutation(arr1)

#결과
array([[3, 4, 5],
       [6, 7, 8],
       [0, 1, 2]])
       
np.random.permutation(arr2)

#결과
array([[[18, 19, 20],
        [21, 22, 23],
        [24, 25, 26]],

       [[ 0,  1,  2],
        [ 3,  4,  5],
        [ 6,  7,  8]],

       [[ 9, 10, 11],
        [12, 13, 14],
        [15, 16, 17]]])

3x3 메트릭스인 arr1은 맨 앞인 행을 기준으로 랜덤 하게 바뀌는 것을 확인 가능하며 뒤의 열은 섞이지 않는 것을 확인 가능하다.

 

3x3x3 텐서인 arr2는 뒤의 3x3 메트릭스는 바뀌지 않는 것을 확인 가능하며 3개의 메트릭스의 순서만 바뀌는 것을 확인 가능하다.

'Python > numpy' 카테고리의 다른 글

array_like 데이터 타입(data type)  (0) 2022.03.09
난수 생성 - np.random.seed, np.random.RandomState  (0) 2022.03.08

numpy.random 모듈은 python 내장 random 함수를 보강하여 다양한 종류의 확률 분포로부터 효과적으로 표본 값을 생성하는데 사용 가능하다.

 

numpy.random은 매우 큰 표본을 생성하는데 파이썬 내장 모듈보다 수십 배 빠르다. 

 

numpy.random을 엄밀하게 말하면 유사 난수라 부르는데, 이는 난수 생성기의 시드값에 따라 정해진 난수를 알고리즘으로 생성하기 때문이다. 즉, 컴퓨터 프로그램에서 무작위 수를 구할때는 어떠한 특정 시작 숫자를 기준으로 컴퓨터가 정해진 알고리즘에 의해 마치 난수처럼 보이는 수열을 생성한다. 이러한 시작 숫자를 시드(seed)라고 한다. 또한 생성된 난수는 다음번 난수 생성을 위한 시드가 된다. 시드는 보통 자동으로 정해지지만 사람이 수동으로 정할 수 있다.

 

수동으로 시드를 정한다면 이후의 난수들을 예측할 수 있다. 이는 프로그램을 돌릴때 결과의 재현성을 위해 사용한다. 예를 들어 딥러닝 프로그램에 parameter를 특정 시드를 사용하여 정해준다면 parameter의 초기값에 의해 성능이 바뀌는 일이 일어나지 않는다.

 

Numpy의 난수 생성기의 시드값은 다음과 같이 변경 가능하다.

import numpy as np

np.numpy.seed(123)

 이를 이용하여 numpy에서 제공하는 시드값은 전역 난수 시드값을 이용한다.

 

a = np.random.randn(5)

# 결과 
array([-1.0856306 ,  0.99734545,  0.2829785 , -1.50629471, -0.57860025])

b = np.random.randn(5)

# 결과
array([ 1.65143654, -2.42667924, -0.42891263,  1.26593626, -0.8667404 ])

다음의 과정을 본다면 시드를 123으로 준다면 처음 난수 결과값은 항상 -1.0856306이 나올 것이다. 다음 난수 결과값은 -1.0856306을 시드로 사용하여 생성한다.

np.random.seed(123)

a = np.random.randn(1)

# 결과
array([-1.0856306])

b = np.random.randn(1)

#결과
array([0.99734545])

다음과 같이 시드 123을 사용하여 난수을 2개 만들어보면 위의 a의 5개의 난수 값의 처음 두 개와 일치하는 것을 볼 수 있다.

 

여기에서 문제는 np.random.seed를 사용하여 난수를 생성한다면 앞으로 numpy를 사용하여 만드는 모든 난수값이 시드의 값에 영향을 받게 된다. 이는 서로 다른 시드를 사용하고 싶을 때 고려해줄 것이 많게 된다. 따라서 난수 생성기로부터 격리된 난수 생성기를 만들고 싶다면 다음과 같은 코드를 사용하면 된다.

 

np.random.seed(123)
rns = np.random.RandomState(123)

a = np.random.randn(5)

#결과
array([-1.0856306 ,  0.99734545,  0.2829785 , -1.50629471, -0.57860025])

rns.randn(5)

#결과
array([-1.0856306 ,  0.99734545,  0.2829785 , -1.50629471, -0.57860025])

  np.random.RandomState를 사용한다면 rns라는 object가 생기며 이를 통해 난수에 접근 가능하다. 즉 특정 시드값을 기준으로 생성되는 난수가 필요할 때만 접근 가능하다.

 

예를 들어 전역 시드값을 설정해주는 np.random.seed(123)을 주었으면 위에서 보았듯이 난수를 설정하는데 있어 초기값은 -1.0856306이 나와야 하며 a를 통해 난수 5개를 만들었을때 이를 확인 가능하다. 또한 random.RandomState를 통해 생성한 rns난수생성기를 통해 생성된 5개의 난수를 보면 a의 결과와 같은 것을 확인 가능하다. 이는 서로 다르게 시드값이 적용되는 것을 의미한다.

 

'Python > numpy' 카테고리의 다른 글

array_like 데이터 타입(data type)  (0) 2022.03.09
난수 생성 - numpy .random.permutation  (0) 2022.03.09

+ Recent posts