넘파이에는 ndarray 라는 객체가 있는데 레퍼런스에는 그냥 배열(array)로 지칭한다. 아마 파이썬의 기본 객체인 리스트, 튜플, 딕셔너리 와 이름이 겹치지 않으므로 혼동의 여지가 없어서 그런 것 같다. 앞으로도 그냥 배열이라고 하면 numpy.ndarray 객체를 지칭하는 것으로 하겠다.


>>> import numpy as np

이 객체를 생성하는 대표적인 함수가 array() 함수인데 첫 번째 입력인수가 array-like 객체이다. array-like 객체는 다음과 같은 것들이 있다.

 

  • 리스트 (list)

  • 튜플 (tuple)

  • 배열 (ndarray) - 배열 자체도 array()함수의 첫 번째 인자로 올 수 있다.

  • 행렬 (matrix)


예를 들면 다음과 같다.


>>> np.array([1, 2, 3])
     array([1, 2, 3])

>>> np.array([1, 2, 3.0]) # upcasting
    array([ 1.,  2.,  3.])

>>> np.array([[1, 2], [3, 4]]) #More than one dimension:
    array([[1, 2],
          [3, 4]])
>>> np.array([1, 2, 3], ndmin=2) # Minimum dimensions 2
    array([[1, 2, 3]])

>>> np.array([1, 2, 3], dtype=complex) # Type provided:
    array([ 1.+0.j,  2.+0.j,  3.+0.j])

>>> np.array(np.mat('1 2; 3 4')) # Creating an array from sub-classes:
    array([[1, 2],
           [3, 4]])

>>> np.array(np.mat('1 2; 3 4'), subok=True)
    matrix([[1, 2],
            [3, 4]])

 넘파이로 코딩하면서 직접 확인한 몇 가지 사실들을 아래에 기록해 보았다. (혹시 오류가 있다면 댓글을 남져주시길 부탁드립니다.)


스칼라 상수(변수)로 생성된 배열은 0차 배열 이다.

스칼라로 배열을 생성할 경우 배열 객체의 차수는 0차이다. 즉, 스칼라는 0차 배열이다. shape은 empty tuple을 가지고 size는 1이다.


>>> x= 10
>>> a = np.array(x)
>>> a.ndim, a.shape, a.size
     (0, (), 1)


0차 배열이라는 용어가 생소하겠지만 배열에 스칼라도 포함된다는 것이 더 논리적인 것 같다. 만약 단일 수에서 1차 배열을 생성하려면 다음과 같이 리스트(혹은 튜플)로 만들어서 넘겨야 한다.

>>> a = np.array( [x] ) # 혹은 a = np.array( (x,) )
>>> a.ndim, a.shape, a.size
     (1, (1,), 1)


이것은 요소가 한 개인 1차 배열이 된다. 즉 np.array(10) 과 np.array([10])은 엄연히 구별된다. 전자는 0차 배열, 후자는 1차 배열이다.


2차 배열에서 크기가 다른 행은 리스트다.

이것은 예를 들어서 다음과 같은 배열 a와 b를 고려해 보자.


>>> a = np.array( [ [1,2], [3,4] ] )
>>> b = np.array( [ [1,2], [3,4,5] ] )


두 변수는 모두 배열이다. 하지만 배열 a의 각 요소 a[0] 과 a[1] 은 type 이 배열인 반면 b[0], b[1] 은 리스트이다. 즉, 변수 a 는 array of array 이고 변수 b는 array of list 이다. 따라서 a[0] 은 배열의 모든 속성을 사용할 수 있지만 b[0]는 리스트이기 때문에 그럴 수 없다.


 만약 크기가 다른 행들도 모두 배열로 만들고 싶다면 다음과 같이 하면 된다.


>>> a = np.array( [ np.array([1,2]) , np.array([1,2,3]) ] )


이것은 array of array 가 된다.


리스트와 배열의 연산 결과는 배열이다.

 리스트끼리의 산술 연산은 정의되어 있지 않으나 리스트와 배열 상호간 연산은 요소간 연산이 적용된다. 그리고 그 결과도 배열이다.


>>> [1,2,3]/2 # 에러가 발생한다.
>>> [1,2,3]/np.asarray([2])
    array([ 0.5,  1. ,  1.5])


위의 두 번째 명령의 결과를 보면 연산 결과도 배열임을 알 수 있다.



Posted by 살레시오
,

 Scilab의 기본 데이타형은 행렬(matrix)이며 스칼라도 내부적으로는 1x1행렬로 취급된다. 벡터도 마찬가지로 nx1 행렬 (열벡터) 혹은 1xn 행렬 (행벡터) 로 취급된다. 행렬의 요소는 숫자, 불리언, 문자열, 다항식 등 일반적인 Scilab 객체가 될 수 있다. 일 반적으로 그냥 벡터라 하면 열벡터(column vector)를 의미하는 경우가 많으므로 앞으로 그냥 벡터라고 하면 열벡터를 지칭하며 행벡터는 명시적으로 표기하도록 하겠다.


 함수에 넘겨주는 입력 파라메터도 행렬이고 함수의 수행 결과 생성되는 출력값도 역시 행렬이다. 편의상  다음과 같이 구분한다.

❶ 스칼라 : 1x1 차원의 행렬

❷ 벡터 : nx1 차원의 행렬 (행벡터는 1xn 행렬), n ≥ 1 인 정수(스칼라 포함)

❸ 행렬 : mxn 차원의 행렬, m,n ≥ 1 인 정수 (스칼라, 벡터포험)

 행렬을 입력할 때는 대괄호 [ ] 를 사용하며 콤마(,)나 공백을 이용하여 요소 간을 구별한다. 세미콜론(;) 혹은 다음 줄이 행들을 구분한다. (이것은 Matlab 이나 Octave와 동일하다.) 따라서 다음 네 가지가 완전히 동일한 2x3 행렬을 생성한다.

>> A = [1, 2, 3; 4, 5, 6]
>> A = [1 2 3; 4 5 6]
>> A = [1,2,3
4,5,6]
>> A = [1 2 3
4 5 6]

행이 두 개 이상일 때는 반드시 행들의 요소 갯수가 같아야 함에 유의해야 한다. 예를 들어서 다음과 같은 입력은 에러를 발생시킬 것이다. 왜냐하면 1행의 크기는 3인데 2행의 크기는 2이기 때문이다.


>> B = [ 1 2 3; 4 5]

행렬의 요소는 복소수도 가능하고 문자열도 가능하다. 예를 들어 다음과 같다.

복소행렬을 생성할 때 주의할 점은 실수부와 허수부사이에 공백문자가 있으면 안된다는 것이다. 다음의 C행렬과 D행렬은 크기가 다른 행렬이 되버린다.(왜?)


>> C = [2+3*%i, 4]
>> D = [2 +3*%i, 4]

 

문자열을 요소로 하는 행렬도 가능하다. 예를 들면 다음과 같다.

>> E = [“abc” “def”]
>> F = [“hello”, “world”; “My name is”, ‘Salecio’]    

그러나 한 행렬의 요소들이 숫자나 문자열이 섞일 수는 없다. 또한 정수형과 실수형은 데이터형이 다르기 때문에 한 행렬에 섞일 수도 없다. 따라서 다음과 같은 입력은 에러를 발생시킨다.


>> G = [ 1 2; ‘abc’, 4]
>> K = [int8(1) 2; 3 4]

 

첫 번째 G는 숫자와 문자열을 한 행렬에 섞어서 입력했기 때문에 에러를 발생하며 두 번째 K는 정수형과 실수형이 섞여있기 때문에 에러를 발생한다.

 반면에 진리값을 나타내는 %T(혹은 %t) 와 %F( 혹은 %f)는 특수한 상수이지만 내부적으로 (더블형) 실수 1과 0으로 취급된다. 따라서 이들 값을 숫자형과 섞어서 사용할 수 있다.

이미 생성된 행렬을 이용하여 새로운 행렬을 생성할 수도 있다.

>> A = [ 1 2; 3 4]
>> B = [ A; 5 6]
>> C = [ A [5 6; 7 8] ]
>> D = [A A]
>> E = [A; A]

두 행렬을 옆으로 연결할 때에는 행의 수가 같아야하고 위아래로 연결할 때는 열의 수가 같아야 에러가 발생하지 않는다.

콜론(:) 연산자

 행벡터 혹은 열벡터를 입력하거나, 생성시켜야 하는 경우에 각 벡터 요소들의 증가분이나  감소분이 일정한 경우가 있다. 이 경우에는 콜론(:) 연산자를 이용하면 된다. 이 연산자는 사용 빈도가 높으므로 잘 숙지해 두어야 한다. 입력형식은 아래와 같다.


>> 변수 = 초기값:증감값:최종


이 명령은 초기값으로부터 최종값까지 증감값만큼 증감시킨 수열을 요소로 갖는 행벡터를 생성하여 변수에 저장하게 된다. (행벡터를 생성한다는데 주의하자!) 예를 들어, 변수 a에 0부터 100까지 10의 간격으로 행벡터를 만들고자 한다면 다음과 같이 입력하여 실행한다.



만약 증가분이 1이라면 이것은 생략할 수 있다. 만약 0부터 20까지 1씩 증가시킨 값들을 요소로 갖는 행벡터를 만들고 싶다면 다음과 같이 한다.


>> b=1:20

 

10부터 1씩 감소시켜서 0까지의 값을 요소로 갖는 행벡터는 다음과 같이 생성할 수 있다.

>> c = 10:-1:0

콜론 연산자는 사용 빈도가 굉장히 높으므로 잘 숙지하고 있어야 한다.



Posted by 살레시오
,

 리스트는 여러 개의 객체를 하나로 묶는 데이터 형이다. (엄밀히 말하면 mutable sequence 형임) 기본적으로 대괄호 [..]를 이용하여 묶고자 하는 데이터들을 콤마(,)로 구별하여 나열한다. 보통은 같은 형의 데이터를 묶어서 많이 사용하지만 리스트의 요소는 서로 다른 데이터 형일 수 있다.


>>> la = [11, 22, 33] # 리스트를 생성하여 la 에 저장한다.
>>> lb = [‘life’, ‘is’, ‘short’] # 문자열의 리스트
>>> lc = [True, ‘hi’, 33.4, 2-3j]
>>> ld = [] # empty list를 생성하여 lc에 저장


이 예제와 같이 리스트의 요소는 어떠한 자료형이라도 가능하다. 리스트 안에 리스트가 오는 것도 얼마든지 가능하다.


>>> le = [ [11,22], [33, 44, 55] ]


이것을 중첩된 리스트라고 한다.


리스트를 만드는 또 다른 방법은 list comprehension 을 이용하는 것이다. 예를 들어서 제곱 수의 리스트틀 만든다고 가정하자. 다음과 같이 for 문을 이용할 수 도 있을 것이다.


>>> squares = []
>>> for x in range(10):
...    squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]


하지만 이 방법은 변수 x가 생성되고 for 문이 종료된 후에도 변수 x 가 메모리에 남아 있게 된다. 좀 더 깔끔한 방법은 다음과 같이 map()과 익명 함수를 이용하는 것이다.


>>> squares = list(map(lambda x: x**2, range(10)))


이것과 완전히 동일한 방법이 바로 다음과같은 list comprehension 이고 훨씬 더 간결하고 가독성이 높다.


>>> squares = [x**2 for x in range(10)]


일반적으로 다음과 같이 구성된다.


[ 표현식 for문 (for 문 | if 문)* ]


예를 들어서 두 리스트 요소 중 다른 것들로만 조합하는 리스트는 다음과 같다.


>>> [(x,y) for x in [1,2,3] for y in [3,1,4] if x!=y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]


이것은 다음 프로그램과 동일한 동작을 수행한다.


>>> combs = []
>>> for x in [1,2,3]:
...    for y in [3,1,4]:
...        if x != y:
...            combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]


두 가지 경우에서 for 문과 if 문의 순서가 같다는 것을 알 수 있다.

표현식이 튜플일 경우 반드시 괄호로 묶어야 한다.


>>> [(x,x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]


만약 다음과 같이 괄호를 생략하면 에러가 발생한다.


>>> [ x,x**2  for x in range(6)] # 에러 발생


여기서 소개한 내용이 리스트를 생성하는 기본적인 방법들이다.



Posted by 살레시오
,