지난번 포스팅에서는 같은 차원 크기의 배열 간 산술연산인 Vectorization 에 대해서 소개하였습니다.

 

이번 포스팅에서는 차원의 크기가 서로 다른 배열 간 산술연산 시의 Broadcasting 에 대해서 알아보겠습니다. (Braodcasting도 Vectorization 의 일부분 입니다. 사실, 지난번 vectorization에서 Scalar와의 연산 시 element-wise 연산 시 이미 Broadcasting을 맛보았었습니다. ㅎㅎ

 

Broadcasting이 서로 다른 모양, 크기의 배열 간 연산이다 보니 좀 헷갈릴 수도 있는데요, 알아두면 매우 편리하고 또 빠른 연산으로 유용합니다. 이해하기 쉽도록 Broadcasting 되는 모습을 이미지(점선 & 화살표)로 표현을 병행했습니다.

 

배열의 차원(Dimension)과 축(Axis) 별로 4가지 유형의 Broadcasting 을 차례대로 소개해보겠습니다.

 

 1) Broadcasting over axis 1 with a Scalar

 2) Broadcasting over axis 0 with a 1-D array

 3) Broadcasting over axis 1 with a 2-D array

 4) Broadcasting over axis 0 with a 3-D array

 

 

순서대로 예를 들어 살펴보겠습니다.

 

 1) Broadcasting over axis 1 with a Scalar 

 

먼저, 간단한 Scalar 부터 시작해보시지요.

 

 

 

# (1-1) Arithmetic operations between array and scalars
# : the scalar are broadcasted along the same dimensions of ndarray

 

In [1]: import numpy as np


In [2]: a_ar = np.array([1., 2., 3., 4.])


In [3]: a_ar.shape

Out[3]: (4,)


In [4]: a_ar + 1

Out[4]: array([ 2., 3., 4., 5.])

 

 

 

 

배열 뿐만 아니라 Pandas의 DataFrame 도 Scalar 산술 연산 시에 Broadcasting 이 적용됩니다.  간단한 예를 들어볼겠요.

 

 

# (1-2) Arithmetic operations between DataFrame and scalars
# : the scalar are broadcasted along the same dimensions of DataFrame

 

In [5]: import pandas as pd


In [6]: a_df = pd.DataFrame({'x1': [1, 2, 3, 4], 'x2': [5, 6, 7, 8]})


In [7]: a_df

Out[7]:

  x1 x2

0 1 5

1 2 6

2 3 7

3 4 8


In [8]: a_df + 1

Out[8]:

  x1 x2

0 2 6

1 3 7

2 4 8

3 5 9

 

 

 

 

자, 이제 차원을 하나 늘려볼까요?

 

 2) Broadcasting over axis 0 with a 1-D array

 

세로 방향(over axis 0)으로 row를 복사해가면서 Braodcasting을 하는 예입니다.

 

 

 

## (2) Broadcasting using a 1-D array
# Arithmetic operations between 2-D array and 1-D array
# that is the same length as the row-length

 

In [9]: b = np.arange(12).reshape((4, 3))


In [10]: b.shape

Out[10]: (4, 3)


In [11]: b

Out[11]:

array([[ 0, 1, 2],

        [ 3, 4, 5],

        [ 6, 7, 8],

        [ 9, 10, 11]])


In [12]: c = np.array([0, 1, 2])


In [13]: c.shape

Out[13]: (3,)


In [14]: c

Out[14]: array([0, 1, 2])

 

# adding c (1-D array) row-wise to b (2-D array)

In [15]: b + c

Out[15]:

array([[ 0, 2, 4],

        [ 3, 5, 7],

        [ 6, 8, 10],

        [ 9, 11, 13]])

 

 

 

 

배열의 차원 크기, 모양이 다르다고 해서 Broadcasting 이 아무때나 되는 것은 아닙니다. Broadcasting을 시키려면 기준 축에 있는 원소의 크기(개수)가 서로 같아야지 짝을 맞추어서 확산(broadcasting, propagating)을 할 수 있습니다. 말로 설명하기가 좀 어렵습니다. ^^; 아래에 Broadcasting이 안되고 ValueError가 난 사례를 예로 들어보겠습니다.

 

  ValueError: operands could not be broadcast together with shapes (4,3) (4,)

 

 

## Shape mismatches
# ValueError: operands could not be broadcast together with shapes (4,3) (4,)

 

In [11]: b

Out[11]:

array([[ 0, 1, 2],

        [ 3, 4, 5],

        [ 6, 7, 8],

        [ 9, 10, 11]])

 

In [16]: d = np.array([0, 1, 2, 3])


In [17]: b + d

Traceback (most recent call last):


File "<ipython-input-17-8c4237e65878>", line 1, in <module>

b + d


ValueError: operands could not be broadcast together with shapes (4,3) (4,)

 

 

 

 

  3) Broadcasting over axis 1 with a 2-D array

 

가로 방향(over axis 1)으로 column을 복사해가면서 broadcasting하는 예입니다.

 

 

 

## (3) Broadcasting over axis 1 of a 2-D array

 

In [18]: b = np.arange(12).reshape((4, 3))


In [19]: b.shape

Out[19]: (4, 3)


In [20]: b

Out[20]:

array([[ 0, 1, 2],

        [ 3, 4, 5],

        [ 6, 7, 8],

        [ 9, 10, 11]])


In [21]: e = np.array([0, 1, 2, 3]).reshape(4, 1)


In [22]: e.shape

Out[22]: (4, 1)


In [23]: e

Out[23]:

array([[0],

        [1],

        [2],

        [3]])

 

# adding e (2-D array) column-wise to b (2-D array)

In [24]: b + e

Out[24]:

array([[ 0, 1, 2],

        [ 4, 5, 6],

        [ 8, 9, 10],

        [12, 13, 14]])

 

 

 

 

자, 이제 3차원으로 넘어가보겠습니다.  머리가 슬슬 아파오지요? ^^;

4차원부터는 그림으로 예시를 들기가 애매해서 3차원까지만 할께요.

 

  4) Broadcasting over axis 0 with a 3-D array

 

3-D 배열에서 앞뒤 방향(over axis 0) 으로 2-D 배열을 복사해가면서 Broadcasting 하는 예제입니다.

 

 

 

## (4) Broadcasting over axis 0 of a 3-D array
# 3-D array

 

In [25]: f = np.arange(24).reshape((2,4,3))


In [26]: f

Out[26]:

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]]])

 

 

# 2-D array

In [27]: g = np.ones((4,3))


In [28]: g

Out[28]:

array([[ 1., 1., 1.],

        [ 1., 1., 1.],

        [ 1., 1., 1.],

        [ 1., 1., 1.]])

 

 

# Broadcasting over axis 0 of a 3-D array : 3-D array + 2-D array

In [29]: f + g

Out[29]:

array([[[ 1., 2., 3.],

         [ 4., 5., 6.],

         [ 7., 8., 9.],

         [ 10., 11., 12.]],


        [[ 13., 14., 15.],

         [ 16., 17., 18.],

         [ 19., 20., 21.],

         [ 22., 23., 24.]]])

 

 


* 서로 다른 차원을 가진 두 배열의 산술연산 시 repeat(n, axis) 메소드를 통해 차원을 맞추어주는 방법은 https://rfriend.tistory.com/549 를 참고하세요. 

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡'를 꾹 눌러주세요. ^^

 

728x90
반응형
Posted by Rfriend
,

Python을 활용한 기계학습이나 딥러닝 공부하다보면 NumPy 연산이 기본으로 깔려있습니다.  NumPy를 알고 있으면 공부하기가 편할 것이고, NumPy를 모르면 암호처럼 보일 거예요.  

 

이번 포스팅에서는 Python NumPy의 배열과 배열, 배열과 스칼라 연산 (Numerical Operations between Arrarys and Scalars) 에 대해서 알아보겠습니다. 별로 어렵지는 않습니다.  

 

크기가 같은 두 개의 숫자형 배열에 대해서 산술 연산(arithmetic operations)을 할 때 'for loops'를 사용하지 않고도 NumPy ndarray를 사용하면 Vectorization 으로 매우 빠르게 batch 연산을 수행할 수 있습니다.

 

만약 연산을 하는 두 배열의 차원(dimension, shape)이 다르다면 NumPy는 Broadcasting을 해서 연산을 해주는데요, 이건 다음번 포스팅에서 별도로 소개하겠습니다.

 

 

[ Operations between NumPy Arrarys and Scalars ]

 

 

 

 

먼저 NumPy 모듈을 불러오고 예제 array 를 만들어보겠습니다.

 

 

#%% Numerical Operations between Arrays and Scalars
# vectorization

## importing modules

 

In [1]: import numpy as np


## making an nparray

 

In [2]: x = np.array([1., 1., 2., 2.])


In [3]: y = np.array([1., 2., 3., 4.])


In [4]: x

Out[4]: array([ 1., 1., 2., 2.])


In [5]: y

Out[5]: array([ 1., 2., 3., 4.])

 

 

 

 

 

 (1) 배열과 스칼라의 산술 연산 (Arithmetic operations with an array and scalar)

  • 산술연산 종류 : 덧셈 (addition, +), 뺄셈 (subtraction, -), 곱셈 (multiplication, *), 나눗셈 (division, /), 몫 (floor division, //), 나머지 (modulus, %), 배수 (exponent, **)
  • 연산할 때 스칼라가 배열의 각 원소별로 모두 돌아가면서 연산의 대상으로 적용됨 (한글로 풀어쓰려니 표현이 참... -_-;) (propagating the value to each element).

 

 

## (1) Arithmetic operations with scalars, propagating the value to each element
# (1-1) addition

In [6]: y + 1

Out[6]: array([ 2., 3., 4., 5.])

 

# (1-2) subtraction

In [7]: y - 1

Out[7]: array([ 0., 1., 2., 3.])

 

# (1-3) multiplication

In [8]: y*2

Out[8]: array([ 2., 4., 6., 8.])

 

# (1-4) division

In [9]: y/2

Out[9]: array([ 0.5, 1. , 1.5, 2. ])

 

# (1-5) floor division

In [10]: y//2

Out[10]: array([ 0., 1., 1., 2.])

 

# (1-6) modulus : returns remainder after division

In [11]: y%2

Out[11]: array([ 1., 0., 1., 0.])

 

# (1-7) exponent

In [12]: y**2

Out[12]: array([ 1., 4., 9., 16.])


In [13]: 2**y

Out[13]: array([ 2., 4., 8., 16.])

 

 

 

 

  NumPy 와 Pure Python 속도 비교

 

위에서 NumPy (vectorization) 가 Pure Python (for loops) 보다 많이 빠르다고 했는데요, 한번 벤치마킹 테스트를 해보았습니다.  똑같은 연산 (배열에 스칼라 1 더하기)을 해봤는데요, NumPy가 Pure Python보다 62.4배 빠르네요. 이거 아주 중요해요.  보통 Python 공부하면서 아주 짧고 간단한 예제를 가지고 실습하다보면 NumPy와 Pure Python의 'for loops'의 속도 차이를 못느낄 수 있습니다. 그런데 만약 백만, 천만 row를 가진 big data에 for loop 잘못 썼다가는 몇 시간이 걸려도 연산이 끝나지 않던게, NumPy 잘 사용하면 수 분 안에 끝낼 수 있다는 뜻이거든요.

 

 

## comparison process time between NumPy and Pure Python
# NumPy

In [14]: a = np.arange(1000000)


In [15]: a

Out[15]: array([ 0, 1, 2, ..., 999997, 999998, 999999])


In [16]: %timeit a + 1

1000 loops, best of 3: 1.45 ms per loop

 


# Pure Python

In [17]: b = range(1000000)


In [18]: b

Out[18]: range(0, 1000000)


In [19]: %timeit [i+1 for i in b]

10 loops, best of 3: 90.5 ms per loop

 


# how fast does NumPy than Pure Python?

In [20]: 90.5/1.45

Out[20]: 62.41379310344828

 

 

 

 

 (2) 같은 크기 배열 간 산술 연산

     (Arithmetic elementwise operstions between equal-size arrays)

 

NumPy에서의 x*y 곱은 선형대수에서 쓰는 행렬곱이 아니며, 그냥 같은 위치에 있는 원소들 간의 곱(element-wise multiplication) 이라는 점 유의하세요.

 

 

## (2) Arithmetic elementwise operations between equal-size arrays

In [21]: x

Out[21]: array([ 1., 1., 2., 2.])


In [22]: y

Out[22]: array([ 1., 2., 3., 4.])

 


# (2-1) addition

In [23]: x + y

Out[23]: array([ 2., 3., 5., 6.])


# (2-2) substraction

In [24]: x - y

Out[24]: array([ 0., -1., -1., -2.])


# (2-3) Array multiplication is not matrix multiplication

In [25]: x*y

Out[25]: array([ 1., 2., 6., 8.])


# (2-4) division

In [26]: y/x

Out[26]: array([ 1. , 2. , 1.5, 2. ])

 

# (2-5) floor division : 몫

In [27]: y//x

Out[27]: array([ 1., 2., 1., 2.])


# (2-6) modulus : returns remainder after division, 나머지

In [28]: y%x

Out[28]: array([ 0., 0., 1., 0.])


# (2-7) power

In [29]: y**x

Out[29]: array([ 1., 2., 9., 16.])

 

 

 

 

 (3) 배열 간 비교 연산 (Comparison operations between equal-size arrays)

  • 원소 단위 비교 연산(element-wise comparison) : np.equal(x, y), np.not_equal(x, y), np.greater(x, y), np.greater_equal(x, y), np.less(x, y), np.less_equal(x, y)
  • 원소 단위로 비교 연산을 만족하면 True 반환, 비교 연산을 만족하지 않으면 False 반환함
  • 배열 단위 비교 연산(array-wise comparson) : np.array_equal(x, y)

 

 

## (3) Comparison operations : returns boolean array 

In [30]: x

Out[30]: array([ 1., 1., 2., 2.])

 

In [31]: y

Out[31]: array([ 1., 2., 3., 4.])

 


# element-wise comparisons
# (3-1) np.equal(x, y) : x==y

In [32]: np.equal(x, y)

Out[32]: array([ True, False, False, False], dtype=bool)

 


# (3-2) np.not_equal(x, y) : x != y, x <> y

In [33]: np.not_equal(x, y)

Out[33]: array([False, True, True, True], dtype=bool)

 


# (3-3) np.greater(x, y) : x > y

In [34]: np.greater(x, y)

Out[34]: array([False, False, False, False], dtype=bool)

 

 

# (3-4) np.greater_equal(x, y) : x >= y

In [35]: np.greater_equal(x, y)

Out[35]: array([ True, False, False, False], dtype=bool)

 


# (3-5) np.less(x, y) : x < y

In [36]: np.less(x, y)

Out[36]: array([False, True, True, True], dtype=bool)

 


# (3-6) np.less_equal(x, y) : x <= y

In [37]: np.less_equal(x, y)

Out[37]: array([ True, True, True, True], dtype=bool)

 


# (3-7) array-wise comparisons

In [38]: np.array_equal(x, y)

Out[38]: False


In [39]: z = y.copy()


In [40]: z

Out[40]: array([ 1., 2., 3., 4.])


In [41]: np.array_equal(y, z)

Out[41]: True

 

 

 

 

  (4) 배열 간 할당 연산 (Assignment operations between equal-size arrays)

  • 할당 연산 : Add AND (m += n), Subtract AND (m -= n), Multiply AND (m *= n), Divide AND (m /= n), Floor Division (m //= n), Modulus AND (m %= n), Exponent AND (m **= n)

 

##----------------
## (4) Assignment operattions

 

In [42]: m = np.array([1., 1., 2., 2.])


In [43]: n = np.array([1., 2., 3., 4.])

 


# (4-1) Add AND : +=

In [44]: m += n # equivalent to m = m + n

 

In [45]: m

Out[45]: array([ 2.,  3.,  5.,  6.])

 

 

# m += n  is equivalent to  m = m + n

In [46]: m = np.array([1., 1., 2., 2.])

 

In [47]: m = m + n


In [48]: m

Out[48]: array([ 2., 3., 5., 6.])

 

 

 

# (4-2) Subtract AND : -=

In [49]: m = np.array([1., 1., 2., 2.])


In [50]: m -= n # equivalent to m = m - n


In [51]: m

Out[51]: array([ 0., -1., -1., -2.])

 

 

 

# (4-3) Multiply AND : *=

In [52]: m = np.array([1., 1., 2., 2.])


In [53]: m *= n # equivalent to m = m*n


In [54]: m

Out[54]: array([ 1., 2., 6., 8.])

 

 

 

# (4-4) Divide AND : /=

In [55]: m = np.array([1., 1., 2., 2.])


In [56]: m /= n # equivalent to m = m/n


In [57]: m

Out[57]: array([ 1. , 0.5 , 0.66666667, 0.5 ])

 

 

 

# (4-5) Floor Division : //=

In [58]: m = np.array([1., 1., 2., 2.])


In [59]: m //= n # equivalent to m = m//n


In [60]: m

Out[60]: array([ 1., 0., 0., 0.])

 

 

 

# (4-6) Modulus AND : %=

In [61]: m = np.array([1., 1., 2., 2.])


In [62]: m %= n # equivalent to m = m % n


In [63]: m

Out[63]: array([ 0., 1., 2., 2.])

 

 

 

# (4-7) Exponent AND : **=

In [64]: m = np.array([1., 1., 2., 2.])


In [65]: m **= n # equivalent to m = m**n


In [66]: m

Out[66]: array([ 1., 1., 8., 16.])

 

 

 

 

  (5) 배열 간 논리 연산 (Logical operations between equal-size arrays)

  • 논리 연산
    - np.logical_and(a, b) : 두 배열의 원소가 모두 '0'이 아니면 True 반환 
    - np.logical_or(a, b) : 두 배열의 원소 중 한개라도 '0'이 아니면 True 반환
    - np.logical_xor(a, b) : 두 배열의 원소가 서로 같지 않으면 True를 반환

 

 

##----------------
## (5) Logical operators

In [67]: a = np.array([1, 1, 0, 0], dtype=bool)


In [68]: b = np.array([1, 0, 1, 0], dtype=bool)

 


# (5-1) np.logcal_and : (a and b) is true
# if all of the two operands are non-zero then condition becomes true

# equivalent to infix operators : &

In [69]: np.logical_and(a, b)

Out[69]: array([ True, False, False, False], dtype=bool)

 


# (5-2) np.logical_or : (a or b) is true
# if any of the operands are non-zero then contition becoems true

# equivalent to infix operators : |

In [70]: np.logical_or(a, b)

Out[70]: array([ True, True, True, False], dtype=bool)

 


# (5-3) np.logical_xor : Not (a and b) is false
# used to reverse the logical state of its operand

# equivalent to infix operators : ^

In [71]: np.logical_xor(a, b)

Out[71]: array([False, True, True, False], dtype=bool)

 

 

 

  (6) 소속 여부 판단 연산 (Membership operators)

  • 소속 여부 판단 연산 : in, not in
  • 배열 (혹은 리스트)에 특정 객체들어있으면 True를 반환, 안들어 있으면 False를 반환

 

# (6) Membership operators

In [72]: p = "P"


In [73]: q = np.array(["P", "Q"])


In [74]: r = np.array(["R", "S"])

 


# (6-1) in

In [75]: p in q

Out[75]: True


In [76]: p in r

Out[76]: False

 


# (6-2) not in

In [77]: p not in q

Out[77]: False


In [78]: p not in r

Out[78]: True

 

 

 

 

 배열의 차원, 크기가 다를 때

 => ValueError: operands could not be broadcast together with shapes (4,) (5,) 

 

 

##--------------
## Shape mismatches

In [79]: x4 = np.array([1., 1., 2., 2.])

 

In [80]: x5 = np.arange(5)

 


# ValueError: operands could not be broadcast together with shapes (4,) (5,)

In [81]: x4 + x5

Traceback (most recent call last):


File "<ipython-input-82-5e88af36d6f1>", line 1, in <module>

x4 + x5


ValueError: operands could not be broadcast together with shapes (4,) (5,)

 

 

배열의 차원, 크기가 다를 때 ValueError가 났습니다.  그리고 'broadcast'를 할 수 없다(could not be broadcast together...)는 메시지가 나왔습니다.

 

다음번 포스팅에서는 Broadcasting 에 대해서 알아보겠습니다.

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감~♡'를 눌러주세요. ^^

 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python의 NumPy 모듈을 사용해서

 

 - 데이터 형태 지정 (assign data type) :

 - 데이터 형태 확인 (check data type)

 - 데이터 형태 변경 (convert data type)

 

하는 방법을 소개하겠습니다.

 

다양한 데이터 형태를 자유자재로 다룰 수 있다는 점이 NumPy의 주요 강점 중의 하나이며, 데이터 전처리 단계에서 데이터 형태를 지정하거나 변경(숫자형을 문자형으로, 문자형을 숫자형으로..) 하는 일이 종종 생기므로 기본기로서 꼭 익혀두어야 하는 내용입니다.  어렵지 않으니 내용 한번 훓어보시고, 실습 한번 따라해보세요.

 

 

 

 

 

  (1) 데이터 형태의 종류 (Data Types)

 

데이터 형태(Data Type, dtype)는 크게 숫자형(nuemric)문자형(string)으로 나누며, 숫자형으로 된 데이터 형태에는 bool 자료형(booleans, bool), 정수형 (integers, int), 부호 없는 정수형 (unsigned integers , uint), 부동소수형 (floating point, float), 복소수형 (complex) 의 5가지가 있습니다.

 

NumPy 에서 각 데이터 형태를 나타내는 표기법은 아래와 같으며, 데이터 형태 표기 Type 옆에 써있는 숫자 (8, 16, 31, 64, 128 등)는 단일 값을 메모리에 저장하는데 필요한 bits 수(1 byte = 8 bits)를 의미합니다.

 

아래 표의 Type code는 Type을 줄여서 쓴 표기로서, Type과 똑같이 결과를 반환합니다.

 

 구분

Type 

Type Code 

Example 

 숫자형

(numeric)

 bool형

 (booleans)

 bool

 ?

 [True, True, False, False]

 정수형

 (integers)

 int8

 int16

 int32

 int64

 i1

 i2

 i4

 i8

 [-2, -1, 0, 1, 2, 3]

 부호없는 (양수) 정수형

 (unsigned integers)

 uint8

 uint16

 uint32

 uint64

 u1

 u2

 u4

 u8

 [2, 1, 0, 1, 2, 3]

 부동소수형

 (floating points)

 float16

 float32

 float64

 f2

 f4

 f8

 [-2.0, -1.3, 0.0, 1.9, 2.2, 3.6]

 복수수형(실수 + 허수)

 (complex)

 complex64

 complex128

 c8

 c16

 (1 + 2j)

문자형

(character)

 문자형

 (string)

 string_

 S 

 ['Seoul', 'Busan', 'Incheon']

 

복소수형(complex)는 고등학교 때 배우셨을텐데요, 과학자나 수학자가 아니라면 회사에서 분석업무할 때는 거의 안쓸거 같습니다. 참고로, 수학시간에는 (1+2i) 처럼 허수를 'i'로 표기하면서 배웠을텐데요, Python에서는 (1+2j) 처럼 허수를 'j'로 표기합니다.

 

 

 

NumPy에서 ndarray 만들 때 데이터 형태 지정해주는 3가지 방법을 소개합니다.  저는 첫번째 방법이 눈에 잘 들어오고 이해가 잘 되어서 (비록 좀 길더라도) 주로 사용합니다.

 

 (2) NumPy 데이터 형태 지정해주기

 

(2-1) np.array([xx, xx], dtype=np.Type)

 

 

# importing numpy module

In [1]: import numpy as np


# (2-1) making array with data type of float64: dtype=np.float64

In [2]: x_float64 = np.array([1.4, 2.6, 3.0, 4.9, 5.32], dtype=np.float64)


# checking data type : dtype method

In [3]: x_float64.dtype

Out[3]: dtype('float64')


In [4]: x_float64

Out[4]: array([ 1.4 , 2.6 , 3. , 4.9 , 5.32])

 

 

데이터 형태 확인은 object.dtype 을 사용합니다.

 

 

 

(2-2) np.array([xx, xx], dtype=np.'Type Code')

 

 

# (2-2) making array with shorthand type code string for float64 : dtype='f8'

In [5]: x_float64_1 = np.array([1.4, 2.6, 3.0, 4.9, 5.32], dtype='f8')


In [6]: x_float64_1.dtype

Out[6]: dtype('float64')


In [7]: x_float64_1

Out[7]: array([ 1.4 , 2.6 , 3. , 4.9 , 5.32])

 

 

 

(2-3) np.Type([xx, xx])

 

 

# (2-3) making array with data type of float64 : np.folat64()

In [8]: x_float64_2 = np.float64([1.4, 2.6, 3.0, 4.9, 5.32])


In [9]: x_float64_2.dtype

Out[9]: dtype('float64')


In [10]: x_float64_2

Out[10]: array([ 1.4 , 2.6 , 3. , 4.9 , 5.32])

 

 

 

 

다음으로 데이터 변환하는 방법에 대해서 알아보겠습니다.

 

  (3) 데이터 형태 변환 (converting data type) : object.astype(np.Type)

 

(3-1) float64를 int64로 변환하기 : x_float64.astype(np.int64)

 

float64의 소수점 부분이 int64로 변환 이후에는 짤려나갔습니다(truncated). 

astype 은 새로운 배열을 복사(copy) 한다는 점 참고하세요.

 

 

In [11]: x_float64 # original data

Out[11]: array([ 1.4 , 2.6 , 3. , 4.9 , 5.32])

 

# object.astype(np.int64)

In [12]: x_int64 = x_float64.astype(np.int64) # the decimal parts are truncated


In [13]: x_int64.dtype

Out[13]: dtype('int64')


In [14]: x_int64

Out[14]: array([1, 2, 3, 4, 5], dtype=int64)

 

 

 

 

(3-2) float64를 int64로 변환하기 : np.int64(x_float64)

 

np.int64(object) 는 (1)번에서 소개했던 int64 만드는 방법 중의 하나였습니다.

 

 

In [15]: x_int64_2 = np.int64(x_float64)


In [16]: x_int64_2.dtype

Out[16]: dtype('int64')


In [17]: x_int64_2

Out[17]: array([1, 2, 3, 4, 5], dtype=int64)

 

 

 

 

(3-3) 부동소수형(float64)를 문자열(string)로 변환하기 : x_float64.astype(np.string_)

 

'np.string_' 의 제일 마지막에 '_' 있다는 점 빼먹지 마세요.  실수로 '_' 를 추가한게 아니라 원래 있는거 맞습니다.

 

 

# (3-3) from float64 to string : astype(np.string_)
# fixed-length string type (1 byte per character)

In [18]: x_string = x_float64.astype(np.string_)


In [19]: x_string.dtype

Out[19]: dtype('S32')


In [20]: x_string

Out[20]:

array([b'1.4', b'2.6', b'3.0', b'4.9', b'5.32'],

dtype='|S32')

 

 

 

(3-4) 문자열(string)을 부동소수형(float64)로 변환하기 : x_string.astype(np.float64)

 

 

# (2-4) from string to float64 : astype(np.float64)

In [21]: x_from_string_to_float64 = x_string.astype(np.float64)


In [22]: x_from_string_to_float64

Out[22]: array([ 1.4 , 2.6 , 3. , 4.9 , 5.32])

 

 

 

 

 (4) Python의 int와 NumPy의 int64 비교 

     (difference between Python's native int and NumPy's int64)

 

 

In [23]: x_py = 12345


In [24]: x_np = np.int64(12345)

 

 

아래 비교의 왼쪽은 Python native int에 사용 가능한 연산자(operators)와 methods, attributes 들입니다. 그리고 오른쪽은 NumPy int64에서 사용할 수 있는 연산자(operators)와 methods, attributes 들입니다.  연산자는 큰 차이가 없지만 methods, attributes에서는 NumPy가 훨씬 많음(Python int는 8개 vs. NumPy int64는 68개, 약 8배 차이)을 알 수 있습니다.  이게 바로 NumPy가 강력하다고 하는 이유 중의 하나입니다.

 

 In [25]: dir(x_py)

Out[25]:

# python's native int operators

['__abs__',

'__add__',

'__and__',

'__bool__',

'__ceil__',

'__class__',

'__delattr__',

'__dir__',

'__divmod__',

'__doc__',

'__eq__',

'__float__',

'__floor__',

'__floordiv__',

'__format__',

'__ge__',

'__getattribute__',

'__getnewargs__',

'__gt__',

'__hash__',

'__index__',

'__init__',

'__int__',

'__invert__',

'__le__',

'__lshift__',

'__lt__',

'__mod__',

'__mul__',

'__ne__',

'__neg__',

'__new__',

'__or__',

'__pos__',

'__pow__',

'__radd__',

'__rand__',

'__rdivmod__',

'__reduce__',

'__reduce_ex__',

'__repr__',

'__rfloordiv__',

'__rlshift__',

'__rmod__',

'__rmul__',

'__ror__',

'__round__',

'__rpow__',

'__rrshift__',

'__rshift__',

'__rsub__',

'__rtruediv__',

'__rxor__',

'__setattr__',

'__sizeof__',

'__str__',

'__sub__',

'__subclasshook__',

'__truediv__',

'__trunc__',

'__xor__',

 

# python's native int methods and attributes

'bit_length',

'conjugate',

'denominator',

'from_bytes',

'imag',

'numerator',

'real',

'to_bytes']

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 In [26]: dir(x_np)

Out[26]:

# numpy's int64 operators

['T',

'__abs__',

'__add__',

'__and__',

'__array__',

'__array_interface__',

'__array_priority__',

'__array_struct__',

'__array_wrap__',

'__bool__',

'__class__',

'__copy__',

'__deepcopy__',

'__delattr__',

'__dir__',

'__divmod__',

'__doc__',

'__eq__',

'__float__',

'__floordiv__',

'__format__',

'__ge__',

'__getattribute__',

'__getitem__',

'__gt__',

'__hash__',

'__index__',

'__init__',

'__int__',

'__invert__',

'__le__',

'__lshift__',

'__lt__',

'__mod__',

'__mul__',

'__ne__',

'__neg__',

'__new__',

'__or__',

'__pos__',

'__pow__',

'__radd__',

'__rand__',

'__rdivmod__',

'__reduce__',

'__reduce_ex__',

'__repr__',

'__rfloordiv__',

'__rlshift__',

'__rmod__',

'__rmul__',

'__ror__',

'__round__',

'__rpow__',

'__rrshift__',

'__rshift__',

'__rsub__',

'__rtruediv__',

'__rxor__',

'__setattr__',

'__setstate__',

'__sizeof__',

'__str__',

'__sub__',

'__subclasshook__',

'__truediv__',

'__xor__',

 

# numpy's int64 methods and attributes

'all',

'any',

'argmax',

'argmin',

'argsort',

'astype',

'base',

'byteswap',

'choose',

'clip',

'compress',

'conj',

'conjugate',

'copy',

'cumprod',

'cumsum',

'data',

'denominator',

'diagonal',

'dtype',

'dump',

'dumps',

'fill',

'flags',

'flat',

'flatten',

'getfield',

'imag',

'item',

'itemset',

'itemsize',

'max',

'mean',

'min',

'nbytes',

'ndim',

'newbyteorder',

'nonzero',

'numerator',

'prod',

'ptp',

'put',

'ravel',

'real',

'repeat',

'reshape',

'resize',

'round',

'searchsorted',

'setfield',

'setflags',

'shape',

'size',

'sort',

'squeeze',

'std',

'strides',

'sum',

'swapaxes',

'take',

'tobytes',

'tofile',

'tolist',

'tostring',

'trace',

'transpose',

'var',

'view']

 

 

많은 도움 되었기를 바랍니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡'를 꾹 눌러주세요. ^^

 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 시간과 비용 문제로 전수 조사를 못하므로 표본 조사를 해야 할 때, 기계학습 할 때 데이터셋을 훈련용/검증용/테스트용으로 샘플링 할 때, 또는 다양한 확률 분포로 부터 데이터를 무작위로 생성해서 시뮬레이션(simulation) 할 때 사용할 수 있는 무작위 난수 만들기(generating random numbers, random sampling)에 대해서 알아보겠습니다.

 

Python NumPy는 매우 빠르고(! 아주 빠름!!) 효율적으로 무작위 샘플을 만들 수 있는 numpy.random 모듈을 제공합니다. 

 

 

 

 

NumPy 를 불러오고, 정규분포(np.random.normal)로 부터 개수가 5개(size=5)인 무작위 샘플을 만들어보겠습니다. 무작위 샘플 추출을 할 때마다 값이 달라짐을 알 수 있습니다.

 

 

 

In [1]: import numpy as np


In [2]: np.random.normal(size=5)

Out[2]: array([-0.02030555, 0.38279633, -1.02369692, 1.48083476, -0.44058273])


In [3]: np.random.normal(size=5) # array with different random numbers

Out[3]: array([ 1.11942454, -1.03486318, 1.69015608, -0.43601241, -1.52195043])

 

 

 

 

먼저, seed와 size 모수 설정하는 것부터 소개합니다.

 

  seed : 난수 생성 초기값 부여

 

난수 생성 할 때 마다 값이 달라지는 것이 아니라, 누가, 언제 하든지 간에 똑같은 난수 생성을 원한다면 (즉, 재현가능성, reproducibility) seed 번호를 지정해주면 됩니다.

 

 

# seed : setting the seed number for random number generation for reproducibility

In [4]: np.random.seed(seed=100)


In [5]: np.random.normal(size=5)

Out[5]: array([-1.74976547, 0.3426804 , 1.1530358 , -0.25243604, 0.98132079])

 


# exactly the same with the above random numbers

In [6]: np.random.seed(seed=100)


In [7]: np.random.normal(size=5) # 위의 결과랑 똑같음

Out[7]: array([-1.74976547, 0.3426804 , 1.1530358 , -0.25243604, 0.98132079])

 

 

 

 

  size : 샘플 생성(추출) 개수 및 array shape 설정

 

다차원의 array 형태로 무작위 샘플을 생성할 수 있다는 것도 NumPy random 모듈의 장점입니다.

 

 

# size : int or tuple of ints for setting the shape of nandom number array

In [8]: np.random.normal(size=2)

Out[8]: array([ 0.51421884, 0.22117967])


In [9]: np.random.normal(size=(2, 3))

Out[9]:

array([[-1.07004333, -0.18949583, 0.25500144],

        [-0.45802699, 0.43516349, -0.58359505]])


In [10]: np.random.normal(size=(2, 3, 4))

Out[10]:

array([[[ 0.81684707, 0.67272081, -0.10441114, -0.53128038],

         [ 1.02973269, -0.43813562, -1.11831825, 1.61898166],

         [ 1.54160517, -0.25187914, -0.84243574, 0.18451869]],


        [[ 0.9370822 , 0.73100034, 1.36155613, -0.32623806],

         [ 0.05567601, 0.22239961, -1.443217 , -0.75635231],

         [ 0.81645401, 0.75044476, -0.45594693, 1.18962227]]])

 

 

 

 

다양한 확률 분포로부터 난수를 생성해보겠습니다.  먼저, 정수를 뽑는 이산형 확률 분포(discrete probability distribution)인 (1-1) 이항분포, (1-2) 초기하분포, (1-3) 포아송분포로 부터 무작위 추출하는 방법을 알아보겠습니다.

 

각 확률분포에 대한 설명까지 곁들이면 포스팅이 너무 길어지므로 참고할 수 있는 포스팅 링크를 걸어놓는 것으로 갈음합니다.

 

- 이항분포 (Binomial Distribution) :  http://rfriend.tistory.com/99

- 초기하분포 (Hypergeometric distribution) :  http://rfriend.tistory.com/100

- 포아송 분포 (Poisson Distribution) :  http://rfriend.tistory.com/101

 

 

  (1-1) 이항분포로 부터 무작위 표본 추출 (Random sampling from Binomial Distribution) : np.random.binomial(n, p, size)

 

앞(head) 또는 뒤(tail) (n=1) 가 나올 확률이 각 50%(p=0.5)인 동전 던지기를 20번(size=20) 해보았습니다. 

 

 

# (1) 이산형 확률 분포 (Discrete Probability Distribution)
# (1-1) 이항분포 (Binomial Distribution) : np.random.binomial(n, p, size)
#       : 복원 추출 (sampling with replacement)
#       : n an integer >= 0 and p is in the interval [0,1]

 

In [11]: np.random.binomial(n=1, p=0.5, size=20)

Out[11]: array([0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1])


In [12]: sum(np.random.binomial(n=1, p=0.5, size=100) == 1)/100

Out[12]: 0.46999999999999997

 

 

 

 

 (1-2) 초기하분포에서 무작위 표보 추출 (Random sampling from Hypergeometric distribution) : np.random.hypergeometric(ngood, nbad, nsample, size)

 

good 이 5개, bad 가 20개인 모집단에서 5개의 샘플을 무작위로 비복원추출(random sampling without replacement) 하는 것을 100번 시뮬레이션 한 후에, 도수분포표를 구해서, 막대그래프로 나타내보겠습니다.

 

 

# (1-2) 초기하분포 (Hypergeometric distribution)
#       : 비복원 추출(sampling without replacement)
#       : np.random.hypergeometric(ngood, nbad, nsample, size=None)

 

In [13]: np.random.seed(seed=100)


In [14]: rand_hyp = np.random.hypergeometric(ngood=5, nbad=20, nsample=5, size=100)


In [15]: rand_hyp

Out[15]:

array([1, 1, 1, 1, 1, 1, 0, 3, 0, 1, 2, 0, 1, 1, 2, 0, 1, 1, 0, 0, 0, 3, 2,
        0, 0, 0, 1, 3, 1, 1, 0, 0, 1, 0, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1, 1, 2,
        1, 0, 1, 1, 2, 1, 2, 1, 2, 0, 1, 2, 1, 1, 0, 1, 0, 1, 0, 1, 1, 2, 0,
        2, 0, 1, 2, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 2, 1, 1, 0, 0, 2, 1, 1,
        1, 1, 1, 1, 1, 3, 1, 0])

 


# result table of 100 simulation

In [16]: unique, counts = np.unique(rand_hyp, return_counts=True)


In [17]: np.asarray((unique, counts)).T

Out[17]:

array([[ 0, 27],
        [ 1, 53],
        [ 2, 16],
        [ 3,  4]], dtype=int64)

 

# bar plot

 In [18]: import matplotlib.pyplot as plt


In [19]: plt.bar(unique, counts, width=0.5, color="blue", align='center')

Out[19]: <Container object of 4 artists>

 

 

 

 

 

 

 

  (1-3) 포아송분포로 부터 무작위 표본 추출 : np.random.poisson(lam, size)

         (random sampling from Poisson distribution)

 

일정한 단위 시간, 혹은 공간에서 무작위로 발생하는 사건의 평균 회수인 λ(lambda)가 20인 포아송 분포로 부터 100개의 난수를 만들어보겠습니다. 그 후에 도수를 계산하고, 막대그래프로 분포를 그려보겠습니다.

 

 

# (1-3) 포아송 분포 (Poisson Distribution)
# np.random.poisson(lam=1.0, size=None)
# Poisson distribution is the limit of the binomial distribution for large N

 

In [20]: np.random.seed(seed=100)


In [21]: rand_pois = np.random.poisson(lam=20, size=100)


In [22]: rand_pois

Out[22]:

array([21, 19, 22, 14, 26, 15, 25, 25, 19, 25, 15, 24, 21, 13, 26, 23, 21,
        16, 24, 17, 18, 18, 15, 18, 22, 28, 21, 18, 17, 31, 23, 13, 20, 19,
        24, 17, 20, 13, 19, 16, 16, 21, 16, 21, 19, 20, 20, 19, 19, 20, 13,
        29,  9, 13, 20, 29, 15, 15, 21, 20, 21, 18, 16, 20, 23, 18, 22, 14,
        19, 20, 18, 17, 20, 24, 20, 15, 19, 19, 25, 17, 19, 27, 20, 17, 12,
        22, 16, 23, 17, 11, 15, 19, 16, 21, 21, 25, 26, 23, 15, 25])


In [23]: unique, counts = np.unique(rand_pois, return_counts=True)


In [24]: np.asarray((unique, counts)).T

Out[24]:

array([[ 9,  1],
        [11,  1],
        [12,  1],
        [13,  5],
        [14,  2],
        [15,  8],
        [16,  7],
        [17,  7],
        [18,  7],
        [19, 12],
        [20, 12],
        [21, 10],
        [22,  4],
        [23,  5],
        [24,  4],
        [25,  6],
        [26,  3],
        [27,  1],
        [28,  1],
        [29,  2],
        [31,  1]], dtype=int64)


In [25]: plt.bar(unique, counts, width=0.5, color="red", align='center')

Out[25]: <Container object of 21 artists>

 

 

 

 

 

다음으로 연속형 확률분포(continuous probability distribution)인 (2-1) 정규분포, (2-2) t-분포, (2-3) 균등분포, (2-4) F 분포, (2-5) 카이제곱분포로부터 난수를 생성하는 방법을 소개합니다.

 

각 분포별 이론 설명은 아래의 포스팅 링크를 참조하세요.

 

- 정규분포 (Normal Distribution) :  http://rfriend.tistory.com/102

- t-분포 (Student's t-distribution) :  http://rfriend.tistory.com/110

- 균등분포 (Uniform Distribution) :  http://rfriend.tistory.com/106

- F-분포(F-distribution) :  http://rfriend.tistory.com/111

- 카이제곱분포 (Chisq-distribution) :  http://rfriend.tistory.com/112

 

 

  (2-1) 정규분포로부터 무작위 표본 추출 : np.random.normal(loc, scale, size)

         (random sampling from Normal Distribution)

 

평균이 '0', 표준편차가 '3'인 정규분포로 부터 난수 100개를 생성해보고, 히스토그램을 그려서 분포를 bin 구간별 빈도(frequency)와 표준화한 비율(normalized percentage)로 살펴보겠습니다.

 

 

# (2) 연속형 확률분포 (continuous probability distribution)
# (2-1) 정규분포(normal distribution)로부터 난수 생성
# Draw random samples from a normal (Gaussian) distribution
# np.random.normal(loc=0.0, scale=1.0, size=None)
# mu : Mean (“centre”) of the distribution
# sigma : Standard deviation (spread or “width”) of the distribution
# size : Output shape

 

In [26]: np.random.seed(100)


In [27]: mu, sigma = 0.0, 3.0


In [28]: rand_norm = np.random.normal(mu, sigma, size=100)


In [29]: rand_norm

Out[29]:

array([-5.24929642,  1.02804121,  3.45910741, -0.75730811,  2.94396236,
        1.54265652,  0.66353901, -3.21012999, -0.56848749,  0.76500433,
       -1.37408096,  1.30549046, -1.75078515,  2.45054122,  2.01816242,
       -0.31323343, -1.59384113,  3.08919806, -1.31440687, -3.35495474,
        4.85694498,  4.62481552, -0.75563742, -2.52730721,  0.55355607,
        2.8112466 ,  2.19300103,  4.08466838, -0.97871418,  0.16702804,
        0.66719883, -4.32965099, -2.26905692,  2.44936203,  2.25133428,
       -1.36784078,  3.5688668 , -5.07185048, -4.06919715, -3.69730354,
       -1.63331749, -2.00451521,  0.02194369, -1.83881621,  3.89924422,
       -5.19928687, -2.9499303 ,  1.07252326, -4.84073551,  4.4121416 ,
       -3.56405279, -1.64923858, -2.82013848, -2.48379709,  0.3265904 ,
        1.52342877, -2.58668204,  3.74840923, -0.23883374, -2.66919444,
       -2.64539517,  0.05591685,  0.71353387,  0.04064565, -4.9065882 ,
       -3.13262963,  1.83911665,  2.20861564,  3.08076432, -4.29657183,
       -5.5235649 ,  1.09827968, -0.99533141, -2.06765393,  6.10382268,
       -1.65214324,  2.25135999, -3.92097702,  1.74172001, -3.31356928,
        2.07036441,  2.0606702 , -4.70006259,  2.71492236,  2.3364672 ,
        1.28469861,  0.32661597,  0.0848509 , -1.73647747, -3.5983536 ,
       -5.11785602,  1.10749187,  5.62972028, -1.13071005,  5.49580825,
        0.0090523 , -0.2280704 ,  0.01187278, -0.55504233, -7.46145461])


In [30]: import matplotlib.pyplot as plt

 


# histogram with frequency

In [31]: count, bins, ignored = plt.hist(rand_norm, normed=False)

 

 

 

# histogram with normalized percentage
In [32]: count, bins, ignored = plt.hist(rand_norm, normed=True)

 

 

 

 

 

  (2-2) t-분포로 부터 무작위 표본 추출 : np.random.standard_t(df, size)

         (Random sampling from t-distribution)

 

자유도(degrees of freedom)가 '3'인 t-분포로부터 100개의 난수를 생성하고, 히스토그램을 그려보겠습니다. 

 

 

# (2-2) t-분포 (Student's t-distribution)로부터 난수 생성
# Draw samples from a standard Student’s t distribution with df degrees of freedom
# np.random.standard_t(df, size=None)
# df : Degrees of freedom
# size : Output shape

 

In [33]: np.random.seed(100)


In [34]: rand_t = np.random.standard_t(df=3, size=100)


In [35]: rand_t

Out[35]:

array([-1.70633623,  0.61010003,  0.45753218, -0.85709656, -0.42990712,
       -0.7437467 ,  0.8444005 , -0.4040428 ,  2.13905276, -0.10844638,
        0.67238716,  1.88720362, -2.57340231, -0.69724955, -3.40107659,
       -0.57745433, -0.36487447,  3.95862541,  2.34665412, -0.94310449,
        0.81852816, -0.48391289,  0.01380029, -0.43003718, -2.25784604,
       -0.18216847, -1.21433582,  0.46347964,  0.50024665, -1.1595865 ,
        0.02358778, -1.18879826, -0.38767689,  2.24289791, -2.80798472,
       -2.838893  , -0.39222432, -1.61499121, -1.78498184,  0.44618923,
       -1.5181203 ,  5.44389927,  4.17743903, -0.49617121, -0.02996529,
        0.89595015,  1.14860485, -3.16541308,  0.14279246,  0.83121743,
       -0.32403947,  0.59297222, -0.39750861,  0.57634934,  0.81587478,
       -1.29367024, -0.28580516, -0.48422765, -0.83697192,  0.50702557,
       -1.98915687,  2.92965716, -1.19522074,  0.65511251,  2.12055605,
       -0.03640814, -0.41931018,  3.31199804, -0.61725596,  0.79681204,
        1.86805014, -0.54345259,  3.11909936,  0.86410458,  2.66353682,
        0.23735454, -0.76306875,  0.24471792, -0.13515045,  0.26402784,
        4.68946895,  0.70573709, -0.17783758,  1.85205955, -0.18352788,
       -0.65713104, -0.73674278,  2.16549569,  1.22326388, -0.5112858 ,
       -1.54451989, -1.73428432,  0.46947115,  1.66594804,  0.51687137,
        1.51361314, -2.22193709,  0.89557421,  0.56222653, -0.55564416])

 

 

# histogram

In [36]: import matplotlib.pyplot as plt


In [37]: count, bins, ignored = plt.hist(rand_t, bins=20, normed=True)


 

 

 

 

  (2-3) 균등분포로 부터 무작위 표본 추출 : np.random.uniform(low, high, size)

         (random sampling from Uniform distribution)

 

최소값이 '0', 최대값이 '10'인 구간에서의 균등분포에서 100개의 난수를 만들어 보고, 히스토그램을 그려서 분포를 확인해보겠습니다.

 

 

# (2-3) 균등분포 (Uniform Distribution)로 부터 난수 생성
# Draw samples from a uniform distribution
# np.random.uniform(low=0.0, high=1.0, size=None)
# low : Lower boundary of the output interval
# high : Upper boundary of the output interval
# [low, high) : includes low, excludes high

 

In [38]: np.random.seed(100)


In [39]: rand_unif = np.random.uniform(low=0.0, high=10.0, size=100)


In [40]: rand_unif

Out[40]:

array([ 5.43404942,  2.78369385,  4.24517591,  8.44776132,  0.04718856,
        1.21569121,  6.70749085,  8.25852755,  1.3670659 ,  5.75093329,
        8.91321954,  2.09202122,  1.8532822 ,  1.0837689 ,  2.19697493,
        9.78623785,  8.11683149,  1.71941013,  8.16224749,  2.74073747,
        4.31704184,  9.4002982 ,  8.17649379,  3.3611195 ,  1.75410454,
        3.72832046,  0.05688507,  2.52426353,  7.95662508,  0.15254971,
        5.98843377,  6.03804539,  1.05147685,  3.81943445,  0.36476057,
        8.90411563,  9.80920857,  0.59941989,  8.90545945,  5.76901499,
        7.42479689,  6.30183936,  5.81842192,  0.20439132,  2.10026578,
        5.44684878,  7.69115171,  2.50695229,  2.8589569 ,  8.52395088,
        9.75006494,  8.84853293,  3.59507844,  5.98858946,  3.54795612,
        3.40190215,  1.7808099 ,  2.37694209,  0.44862282,  5.0543143 ,
        3.76252454,  5.92805401,  6.29941876,  1.42600314,  9.33841299,
        9.46379881,  6.02296658,  3.8776628 ,  3.63188004,  2.04345277,
        2.76765061,  2.46535881,  1.73608002,  9.66609694,  9.570126  ,
        5.97973684,  7.31300753,  3.40385223,  0.92055603,  4.63498019,
        5.08698893,  0.88460173,  5.28035223,  9.92158037,  3.95035932,
        3.35596442,  8.05450537,  7.54348995,  3.13066442,  6.34036683,
        5.40404575,  2.96793751,  1.10787901,  3.12640298,  4.5697913 ,
        6.5894007 ,  2.54257518,  6.41101259,  2.00123607,  6.57624806])

 

 

# histogram

 

In [41]: import matplotlib.pyplot as plt


In [42]: count, bins, ignored = plt.hist(rand_unif, bins=10, normed=True)

 

 

 

 

  이산형 균등분포에서 정수형 무작위 표본 추출 : np.random.randint(low, high, size)

  (Random INTEGERS from discrete uniform distribution)

 

이산형 균등분포(discrete uniform distribution)으로 부터 정수형(integers)의 난수를 만들고 싶으면 np.random.randint 를 사용하면 됩니다. 모수 설정은 np.random.uniform()과 같은데요, high에 설정하는 값은 미포함(not include, but exclude)이므로 만약 0부터 10까지 (즉, 10도 포함하는) 정수형 난수를 만들고 싶으면 high=10+1 처럼 '+1'을 해주면 됩니다.

 

 

# np.random.randint : Discrete uniform distribution, yielding integers

 

In [43]: np.random.seed(100)


In [44]: rand_int = np.random.randint(low=0, high=10+1, size=100)


In [45]: rand_int

Out[45]:

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

 

 

# histogram

In [46]: import matplotlib.pyplot as plt


In [47]: count, bins, ignored = plt.hist(rand_int, bins=10, normed=True)


 

 

 

 

  (2-4) F-분포로 부터 무작위 표본 추출 : np.random.f(dfnum, dfden, size)

         (Random sampling from F-distribution)

 

자유도1이 '5', 자유도2가 '10'인 F-분포로 부터 100개의 난수를 만들고, 히스토그램을 그려서 분포를 확인해보겠습니다.

 

 

# (2-4) F-분포 (F-distribution)으로부터 난수 생성
# Draw samples from an F-distribution (Fisher distribution)
# numpy.random.f(dfnum, dfden, size=None)
# dfnum : degrees of freedom in numerator
# dfden : degrees of freedom in denominator

 

In [48]: np.random.seed(100)


In [49]: rand_f = np.random.f(dfnum=5, dfden=10, size=100)


In [50]: rand_f

Out[50]:

array([ 0.17509245,  1.34830314,  0.7250835 ,  0.55013536,  1.49183341,
        1.19802261,  1.24949706,  0.70015548,  0.71890936,  0.37020715,
        4.70371284,  0.86726338,  5.12146941,  0.12848202,  0.68237285,
        0.79663258,  1.36935299,  1.08005188,  0.99311831,  0.15607878,
        3.7778542 ,  2.35609305,  0.16850985,  0.98599364,  1.12567067,
        3.21579679,  0.87982087,  0.38319493,  0.96834789,  1.00428004,
        1.65589171,  1.2581278 ,  1.71881244,  0.11251552,  1.65949951,
        1.15809569,  1.33210756,  0.37989215,  0.252446  ,  1.22409406,
        1.86571485,  0.42345727,  3.52740557,  1.32989807,  2.0095314 ,
        1.20016474,  3.5067706 ,  0.67232354,  2.79268109,  0.38115844,
        1.3978449 ,  0.7089553 ,  2.12685211,  0.73462708,  2.03686026,
        0.50287078,  0.31183315,  1.66994305,  5.36906534,  1.55708073,
        2.66826698,  1.31701804,  0.66126086,  0.19123589,  0.58223398,
        0.41897952,  2.17842598,  0.98481411,  0.46953552,  0.99266818,
        0.4463218 ,  0.43809118,  0.37791494,  2.46417893,  0.91230902,
        0.50247167,  1.0960922 ,  0.61328846,  2.07107491,  0.65524443,
        4.00311763,  1.61430287,  0.16159395,  2.42851301,  1.38124899,
        0.33750889,  1.93776135,  1.55612023,  0.59284748,  0.56785228,
        1.09259657,  1.22611626,  0.0744978 ,  0.10373193,  1.95616674,
        2.29130443,  0.62968361,  0.67477008,  0.60981642,  0.58408102])

 

 

# histogram

In [51]: import matplotlib.pyplot as plt


In [52]: count, bins, ignored = plt.hist(rand_f, bins=20, normed=True)

 

 

 

 

  (2-5) 카이제곱분포로 부터 무작위 표본 추출 : np.random.chisquare(df, size)

         (Random sampling from Chisq-distribution)

 

자유도(degrees of freedom)가 '2'인 카이제곱분포로부터 100개의 난수를 생성하고, 히스토그램을 그려서 분포를 확인해보겠습니다.

 

 

# (2-5) 카이제곱분포 (Chisq-distribution)로 부터 난수 생성
# Draw samples from a chi-square distribution
# np.random.chisquare(df, size=None)
# df : Number of degrees of freedom

In [53]: np.random.seed(100)


In [54]: rand_chisq = np.random.chisquare(df=2, size=100)


In [55]: rand_chisq

Out[55]:

array([  1.56791674e+00,   6.52483769e-01,   1.10509323e+00,
         3.72577379e+00,   9.46005029e-03,   2.59236110e-01,
         2.22187032e+00,   3.49570821e+00,   2.94001314e-01,
         1.71177147e+00,   4.43873095e+00,   4.69425742e-01,
         4.09939940e-01,   2.29423517e-01,   4.96147209e-01,
         7.69095282e+00,   3.33925872e+00,   3.77341773e-01,
         3.38808346e+00,   6.40613699e-01,   1.13022638e+00,
         5.62781567e+00,   3.40364791e+00,   8.19283487e-01,
         3.85739072e-01,   9.33081811e-01,   1.14094971e-02,
         5.81844910e-01,   3.17596456e+00,   3.07450508e-02,
         1.82680669e+00,   1.85169520e+00,   2.22193172e-01,
         9.62350625e-01,   7.43158820e-02,   4.42204683e+00,
         7.91831906e+00,   1.23627383e-01,   4.42450081e+00,
         1.72030053e+00,   2.71331337e+00,   1.98949905e+00,
         1.74379278e+00,   4.13018033e-02,   4.71511953e-01,
         1.57353105e+00,   2.93167254e+00,   5.77218949e-01,
         6.73452471e-01,   3.82643217e+00,   7.37827846e+00,
         4.32309651e+00,   8.91036809e-01,   1.82688432e+00,
         8.76376262e-01,   8.31607381e-01,   3.92226832e-01,
         5.42815006e-01,   9.17994841e-02,   1.40813894e+00,
         9.44019133e-01,   1.79692816e+00,   1.98819039e+00,
         3.07702183e-01,   5.43139774e+00,   5.85166185e+00,
         1.84409785e+00,   9.81282349e-01,   9.02561614e-01,
         4.57179904e-01,   6.48042320e-01,   5.66147763e-01,
         3.81372088e-01,   6.79897935e+00,   6.29369648e+00,
         1.82247546e+00,   2.62832513e+00,   8.32198571e-01,
         1.93144279e-01,   1.24537005e+00,   1.42139617e+00,
         1.85239984e-01,   1.50170184e+00,   9.69653206e+00,
         1.00517243e+00,   8.17731091e-01,   3.27413768e+00,
         2.80768685e+00,   7.51035408e-01,   2.01044435e+00,
         1.55481738e+00,   7.04210092e-01,   2.34838981e-01,
         7.49795080e-01,   1.22121505e+00,   2.15139414e+00,
         5.86749873e-01,   2.04942998e+00,   4.46596145e-01,
         2.14369617e+00])

 

 

# histogram

In [56]: import matplotlib.pyplot as plt


In [57]: count, bins, ignored = plt.hist(rand_chisq, bins=20, normed=True)

 

 

 

 

 

많은 도움 되었기를 바랍니다.

 

pandas DataFrame 에 대한 무작위 표본 추출 방법은 https://rfriend.tistory.com/602 를 참고하세요.



 

 

728x90
반응형
Posted by Rfriend
,

그동안 Python Pandas의 다양한 method, 함수들에 대해서 알아보았습니다.

 

이번 포스팅부터는 Python NumPy에 대해서 연재를 해볼까 합니다.  그동안의 Pandas 포스팅에서 항상 빠지지않고 더불어 불러왔던 모듈이 바로 NumPy 입니다.  [  import numpy as np ] 라고 (거의) 항상 첫번째 줄에 쓰곤했었지요. 

 

약방에서 약 제조 시 빠지지 않고 넣는게 '감초'라면, Python을 가지고 데이터 분석을 할 때 거의 빠지지 않고 등장하는 모듈이 NumPy라고 보면 되겠습니다.  (라티댄스의 퀵~퀵~슬로우~ 스텝이 NumPy, 파트너와 추는 패턴은 Pandas라고 비유해볼 수도 있겠네요. 기본 스텝이 불안정하면 춤을 제대로 출 수가 없지요!)

 

 

NumPy (Numerical Python)로 ndarray 라는 매우 빠르고 공간 효율적며 벡터 연산(vectorized arithmetic operations)이 가능한 다차원 배열(n-dimentional array)을 만들 수 있습니다.

 

그리고 NumPy는 loop 프로그래밍 없이 전체 배열에 대해서 표준 수학 함수를 매우 빠른 속도로 수행할 수 있습니다.  예전에 250만개 row를 가진 DataFrame에 대해서 데이터 전처리하면서 loop 함수를 썼더니 4시간이 지나도 끝나지가 않던것을요, NumPy 함수를 썼더니 단 몇 분만에 끝나서 깜짝 놀란 적이 있습니다. (다르게 얘기하면, Python에서 Loop 돌리는게 속도, 성능에는 아주 안좋습니다. 대용량 데이터에 Loop 쓸 때는 성능 이슈 고려하시길... Loop 안쓰고 NumPy 함수로 대신할 수 있는지 꼭 확인해보세요.)

 

선형대수(Linear Algebra), 무작위 난수 생성(Random number generation) 등에 NumPy를 사용합니다.

 

 

이번 포스팅에서는 다양한 형태의 ndarray를 생성하는 방법에 대해서 알아보겠습니다.

ndarray 의 행과 열 내의 모든 원소는 동일한 형태의 데이터(all of the elements must be the same type)를 가져야 합니다.

 

 

[ Creating NumPy's ndarrary ]

 

* array image source: https://www.pinterest.com/pin/342062534176033515/ 


 

NumPy 모듈을 불어올 때 애칭(alias name)으로 'np' 를 사용합니다.

 

 

# importing numpy module

In [1]: import numpy as np

 

 

 

 

NumPy의 array() 로 ndarray 를 만들어보겠습니다.

 

 

# making ndarrays : np.array() function

In [2]: arr1 = np.array([1, 2, 3, 4, 5])


In [3]: arr1

Out[3]: array([1, 2, 3, 4, 5])

 

 

 

 

list 객체를 먼저 만들고 np.array() 를 사용해서 배열로 변환해도 됩니다.

 

 

In [4]: data_list = [6, 7, 8, 9, 10] # a list


In [5]: arr2 = np.array(data_list) # converting a list into an array


In [6]: arr2

Out[6]: array([ 6, 7, 8, 9, 10])

 

 

 

같은 길이의 여러개의 리스트(lists)를 가지고 있는 리스트(a list)도 np.array()를 사용해서 배열(array)로 변환할 수 있습니다.

 

 

# a list of equal-length lists

In [7]: data_lists = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]


# converting a list of equal-length lists into a multi-dimensional array

In [8]: arr12 = np.array(data_lists)


In [9]: arr12

Out[9]:

array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10]])

 

 

 

 

다차원 배열의 차원과 그룹 안의 원소들의 크기를 확인할 때 array.shape 함수를 사용합니다.  shape에 indexing 을 적용하면 차원, 원소 크기를 각 각 선택해서 반환합니다 (종종 사용함)

 

array.dtype 함수를 사용해서 데이터 유형을 확인할 수 있습니다.

 

 

# a tuple indicating the size of each dimension

In [10]: arr12.shape # (2, 5)

Out[10]: (2, 5)

 

# indexing ndarray.shape[0], ndarray.shape[1]

In [11]: arr12.shape[0] # 2 : n-dimension

Out[11]: 2

 

In [12]: arr12.shape[1] # 5 : size of elements in nested sequence array

Out[12]: 5

 


# an object describing the data type of the array

In [13]: arr12.dtype # dtype('int32')

Out[13]: dtype('int32')

 

 

 

 

np.asarray() 를 사용해서 array 를 만들기도 합니다.

 

 

# np.asarray : Convert the input to an array

In [14]: a = [1, 2, 3, 4, 5] # a list


In [15]: type(a)

Out[15]: list


In [16]: a = np.asarray(a)


In [17]: type(a)

Out[17]: numpy.ndarray

 

 

 

 

대신 np.array()와는 달리 np.asarray()는 이미 ndarray가 있다면 복사(copy)를 하지 않습니다.

 

 

# Existing arrays are not copied

In [18]: b = np.array([1, 2])


In [19]: np.asarray(b) is b

Out[19]: True

 

 

 

 

만약 데이터 형태(data type)이 이미 설정이 되어 있다면, np.asarray() 를 사용해서 array로 변환하려고 할 경우 데이터 형태가 다를 경우에만 복사(copy)가 됩니다.

 

 

# If dtype is set, array is copied only if dtype does not match

In [20]: c = np.array([1, 2], dtype=np.float32)


In [21]: np.asarray(c, dtype=np.float32) is c # not copied

Out[21]: True

 

In [22]: np.asarray(c, dtype=np.float64) is c # copied

Out[22]: False

 

 

 

 

float 데이터 형태를 원소로 가지는 배열을 만들고 싶을 때는 np.asfarray() 함수를 사용합니다.

 

 

# np.asfarrary: Convert input to a floating point ndarray

In [23]: d = [6, 7, 8, 9, 10]


In [24]: np.asfarray(d)

Out[24]: array([ 6., 7., 8., 9., 10.])

 

 

 

 

np.asarray_chkfinite() 함수를 쓰면 배열로 만들려고 하는 데이터 input에 결측값(NaN)이나 무한수(infinite number)가 들어있을 경우 'ValueError'를 반환하게 할 수 있습니다.  np.nan 으로 결측값을 넣어보고, np.inf 로 무한수를 추가해서 확인해보겠습니다.

 

 

# asarray_chkfinite : Convert a list into an array.
# If all elements are finite asarray_chkfinite is identical to asarray

 

In [25]: e = [11, 12, 13, 14, 15]


In [26]: np.asarray_chkfinite(e, dtype=float)

Out[26]: array([ 11., 12., 13., 14., 15.])

 

In [27]: e_2 = [11, 12, 13, np.nan, 15] # with NaN


In [28]: np.asarray_chkfinite(e_2, dtype=float)

ValueError: array must not contain infs or NaNs



In [29]: e_3 = [11, 12, 13, 14, np.inf] # with infinite


In [30]: np.asarray_chkfinite(e_3, dtype=float)

ValueError: array must not contain infs or NaNs

 

 

 

 

np.zeros(), np.ones(), np.empty() 함수는 괄호 안에 쓴 숫자 개수만큼의 '0', '1', '비어있는 배열' 공간을 만들어줍니다.

 

 

# making arrays of 0's or 1's
# np.zeros : Produce an array of all 0's with the given shape and dtype

In [31]: np.zeros(5) # an array of 5 zeros

Out[31]: array([ 0., 0., 0., 0., 0.])

 

# np.ones : Produce an array of all 1's with the given shape and dtype

In [32]: np.ones(10) # an array of 10 ones

Out[32]: array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])

 

# making new arrays by allocating new memory,
# but do not populate with any values like ones and zeros 

In [33]: np.empty(10) # an array of 10 initialized empty-values

Out[33]: array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

 

 

 

 

np.zeros((2, 5)), np.ones((5, 3)), np.empty((4, 3)) 처럼 괄호 안에 tuple을 넣어주면 다차원 배열(multi-dimensional array)을 만들 수 있습니다.

 

 

# multi-dimensional array by passing a tuple for the shape

In [34]: np.zeros((2, 5)) # 2 by 5 array with '0' elements

Out[34]:

array([[ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.]])


In [35]: np.ones((5, 3)) # 5 by 3 array with '1' elements

Out[35]:

aarray([[ 1.,  1.,  1.],
          [ 1.,  1.,  1.],
          [ 1.,  1.,  1.],
          [ 1.,  1.,  1.],
          [ 1.,  1.,  1.]])

 


In [36]: np.empty((4, 3))

Out[36]:

array([[  9.88131292e-324,   0.00000000e+000,   0.00000000e+000],
        [  0.00000000e+000,   0.00000000e+000,   0.00000000e+000],
        [  0.00000000e+000,   0.00000000e+000,   0.00000000e+000],
        [  0.00000000e+000,   0.00000000e+000,   0.00000000e+000]])

 

 

 

 

np.arange() 는 Python의 range() 함수처럼 0부터 괄호안의 숫자 만큼의 정수 배열 값을 '배열'로 반환합니다. (returns not a list, but an array)  이 함수도 종종 사용하는 편이예요.

 

 

# np.arange : an array-valued version of the built-in Python range function
# Like the bulit-in range but returns an ndarray insted of a list

In [38]: f = np.arange(10)


In [39]: f

Out[39]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

 

 

 

 

np.zeros_like(), np.ones_like(), np.empty_like() 함수는 이미 있는 array와 동일한 모양과 데이터 형태를 유지한 상태에서 각 각 '0', '1', '빈 배열'을 반환합니다.

 

 

# np.zeros_like(), np.ones_like(), np.empty_like()
# Return an array of ones or zeros with the same shape and type as a given array

 

In [40]: f_2_5 = f.reshape(2, 5)


In [41]: f_2_5

Out[41]:

ararray([[0, 1, 2, 3, 4],
           [5, 6, 7, 8, 9]])

 

# return an arrary of zeros with the same shape and type

In [42]: np.zeros_like(f_2_5)

Out[42]:

array([[0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0]])

 

# return an arrary of ones with the same shape and type

In [43]: np.ones_like(f_2_5)

Out[43]:

array([[1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1]])

 


# return an arrary of initialized values with the same shape, type

In [44]: np.empty_like(f_2_5)

Out[44]:

array([[0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0]])

 

 

 

 

np.identity() 혹은 np.eye() 함수를 사용하면 대각성분은 '1'이고 나머지 성분은 '0'으로 구성된 정방행렬인 항등행렬(identity matrix) 혹은 단위행렬(unit matrix)을 만들 수 있습니다.

 

특수한 형태의 행렬에 대해서는 아래 포스팅을 참고하세요.

http://rfriend.tistory.com/141

 

 

# np.identity, np.eye : making a square N x N identity matrix, unit matrix 
# identity matrix : 1's on the diagonal and 0's elsewhere

 

In [45]: np.identity(5)

Out[45]:

array([[ 1.,  0.,  0.,  0.,  0.],
        [ 0.,  1.,  0.,  0.,  0.],
        [ 0.,  0.,  1.,  0.,  0.],
        [ 0.,  0.,  0.,  1.,  0.],
        [ 0.,  0.,  0.,  0.,  1.]])

 

In [46]: np.eye(5)

Out[46]:

array([[ 1.,  0.,  0.,  0.,  0.],
        [ 0.,  1.,  0.,  0.,  0.],
        [ 0.,  0.,  1.,  0.,  0.],
        [ 0.,  0.,  0.,  1.,  0.],
        [ 0.,  0.,  0.,  0.,  1.]])

 

 

 

이상 Python NumPy 모듈을 사용해서 ndarray 만드는 방법 소개를 마치겠습니다.

 

많은 도움 되었기를 바랍니다.

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python pandas 의 Series, DataFrame의 행(row)과 열(column)에 대해서

 

 - 생성 (creation)

 - 선택 (selection, slicing and indexing)

 - 삭제 (drop, delete)

 

하는 방법에 대해서 알아보겠습니다.

 

외부 데이터셋을 불러오거나 직접 만든 다음에 데이터 전처리하는데 있어 수시로 사용하는 가장 기본이 되는 데이터 조작 기법이 행, 열 생성, 선택, 삭제입니다.

 

그동안의 포스팅을 따라해보신 분이라면 이미 많이 익숙해졌을 텐데요, 체계적으로 정리도 해보고, 복습도 해볼 겸 예를 들어서 설명해보겠습니다.

 

 

 

 

 

  (1) Series 생성 및 Series 원소 선택 (element selection, indexing)

 

pd.Series() 를 써서 별도의 index label 이 없는 간단한 Series 를 만들어 보겠습니다.

(index는 0, 1, 2, ... 정수가 자동 부여됨)

 

 

# importing library

In [1]: import numpy as np


In [2]: import pandas as pd

 


# pd.Series with ndarrary data

In [3]: Seri = pd.Series([0., 1., 2., 3., 4.])


In [4]: Seri

Out[4]:

0    0.0
1    1.0
2    2.0
3    3.0
4    4.0
dtype: float64

 

 

 

 

이제 Series의 index 위치나 조건을 가지고 indexing 을 해보겠습니다.

 

 

# Slicing pd.Series like ndarray-like

In [5]: Seri[0]

Out[5]: 0.0


In [6]: Seri[:3]

Out[6]:

0    0.0
1    1.0
2    2.0
dtype: float64


In [7]: Seri[Seri >= Seri.mean()]

Out[7]:

2    2.0
3    3.0
4    4.0
dtype: float64


In [8]: Seri[[4, 2, 0]]

Out[8]:

4    4.0
2    2.0
0    0.0
dtype: float64

 

 

 

 

다음으로, index에 label을 할당해준 Series를 만들어보고, 특정 index label을 지정해서 indexing을 해보겠습니다.

 

 

# pd.Series with index name passed

In [9]: Seri_ix = pd.Series([0., 1., 2., 3., 4.], index=['a', 'b', 'c', 'd', 'e'])


In [10]: Seri_ix

Out[10]:

a    0.0
b    1.0
c    2.0
d    3.0
e    4.0
dtype: float64

 


# Slicing with index label

In [11]: Seri_ix[['a', 'b', 'e']]

Out[11]:

a    0.0
b    1.0
e    4.0
dtype: float64


In [12]: Seri_ix.get(['a', 'b', 'e']) # get() method

Out[12]:

a    0.0
b    1.0
e    4.0
dtype: float64

 

 

 

 

특정 index label 을 지정해서 값(value)을 할당해보겠습니다.

 

 

# set values by index label
In [13]: Seri_ix['a'] = 100


In [14]: Seri_ix

Out[14]:

a    100.0
b      1.0
c      2.0
d      3.0
e      4.0
dtype: float64

 

 

 

 

특정 index label 이 Series에 들어있는지 아닌지 확인 (boolean True, False) 해보겠습니다.

 

 

# check index label whether it is or is'not in Series

In [15]: 'a' in Seri_ix

Out[15]: True


In [16]: 'x' in Seri_ix

Out[16]: False

 

 

 

 

 

  (2) DataFrame 행과 열 생성, 선택, 삭제 (creation, selection, drop of row and column)

 

예제로 사용할 간단한 DataFrame을 dict 로 칼럼과 값을 매핑하고, index 를 지정해서 만들어보겠습니다. DataFrame.index 로 index 확인, DataFrame.columns 로 칼럼 확인할 수 있습니다.

 

 

# importing library and making an example DataFrame

In [17]: from pandas import DataFrame


In [18]: df = DataFrame({'C1': [0., 1., 2., 3.],

    ...: 'C2': [4., 5., 6., 7.],

    ...: 'C3': [8., 9., 10., np.nan]},

    ...: index=['R1', 'R2', 'R3', 'R4'])

    ...:


In [19]: df

Out[19]:

     C1   C2    C3
R1  0.0  4.0   8.0
R2  1.0  5.0   9.0
R3  2.0  6.0  10.0
R4  3.0  7.0   NaN

 


# the row and column labels

In [20]: df.index # row labels

Out[20]: Index(['R1', 'R2', 'R3', 'R4'], dtype='object')


In [21]: df.columns # column labels

Out[21]: Index(['C1', 'C2', 'C3'], dtype='object')

 

 

 

 

df_2 = DataFrame(df_1, index=['xx', 'xx'], columns=['xx', 'xx']) 형식처럼 기존 df_1에서 행과 열을 선별해서 df_2라는 새로운 DataFrame을 만들 수 있습니다.

 

 

In [22]: df_R1R3 = DataFrame(df, index=['R1', 'R3'])


In [23]: df_R1R3

Out[23]:

     C1   C2    C3
R1  0.0  4.0   8.0
R3  2.0  6.0  10.0


In [24]: df_C1C3 = DataFrame(df, columns=['C1', 'C3'])


In [25]: df_C1C3

Out[25]:

     C1    C3
R1  0.0   8.0
R2  1.0   9.0
R3  2.0  10.0
R4  3.0   NaN


In [26]: df_R3R1_C3C1 = DataFrame(df, index=['R3', 'R1'], columns=['C3', 'C1'])


In [27]: df_R3R1_C3C1

Out[27]:

      C3   C1
R3  10.0  2.0
R1   8.0  0.0

 

 

 

 

DataFrame에서 칼럼 이름을 지정해서 선별하는 방법은 아래 예시 처럼 df[['xx', 'xx']] 처럼 하면 됩니다.

 

 

# selecting columns from DataFrame

In [28]: df

Out[28]:

     C1   C2    C3
R1  0.0  4.0   8.0
R2  1.0  5.0   9.0
R3  2.0  6.0  10.0
R4  3.0  7.0   NaN


In [29]: df[['C1', 'C2']]

Out[29]:

     C1   C2
R1  0.0  4.0
R2  1.0  5.0
R3  2.0  6.0
R4  3.0  7.0

 

 

 

 

DataFrame에 새로운 칼럼을 만들기때 (1) df['new_column'] = ... 과 (2) df.assign(new_column = ... ) 의 두가지 방법이 있습니다.

 

 

# (1) making a new column

In [30]: df['C4'] = df['C1'] + df['C2']


In [31]: df

Out[31]:

     C1   C2    C3    C4
R1  0.0  4.0   8.0   4.0
R2  1.0  5.0   9.0   6.0
R3  2.0  6.0  10.0   8.0
R4  3.0  7.0   NaN  10.0

 

 

# (2-1) assign() method

In [32]: df = df.assign(C5 = df['C1']*df['C2'])


In [33]: df

Out[33]:

     C1   C2    C3    C4    C5
R1  0.0  4.0   8.0   4.0   0.0
R2  1.0  5.0   9.0   6.0   5.0
R3  2.0  6.0  10.0   8.0  12.0
R4  3.0  7.0   NaN  10.0  21.0

 

# (2-2) the same with the above

In [34]: df.assign(C5 = lambda x: x.C1*x.C2)

Out[34]:

     C1   C2    C3    C4    C5
R1  0.0  4.0   8.0   4.0   0.0
R2  1.0  5.0   9.0   6.0   5.0
R3  2.0  6.0  10.0   8.0  12.0
R4  3.0  7.0   NaN  10.0  21.0

 

 

 

 

DataFrame의 칼럼을 삭제하는 방법에는 (1) df.drop(['xx', 'xx'], 1) 과 (2) del df['xx'] 의 방법이 있습니다.  del df['xx']은 원본 데이터프레임에서 칼럼을 삭제합니다.

 

 

# drop 'C3' column : DataFrame.drop('Column', 1)

In [35]: df_drop_C4C5 = df.drop(['C4', 'C5'], 1)


In [36]: df_drop_C4C5

Out[36]:

     C1   C2    C3
R1  0.0  4.0   8.0
R2  1.0  5.0   9.0
R3  2.0  6.0  10.0
R4  3.0  7.0   NaN

 

 

# delete a column from original DataFrame : del DataFrame['column']

In [37]: df

Out[37]:

     C1   C2    C3    C4    C5
R1  0.0  4.0   8.0   4.0   0.0
R2  1.0  5.0   9.0   6.0   5.0
R3  2.0  6.0  10.0   8.0  12.0
R4  3.0  7.0   NaN  10.0  21.0

 

In [38]: del df['C4']  # delete 'C4' column from the original DataFrame df directly


In [39]: del df['C5']  # delete 'C5' column from the original DataFrame df directly


In [40]: df

Out[40]:

     C1   C2    C3
R1  0.0  4.0   8.0
R2  1.0  5.0   9.0
R3  2.0  6.0  10.0
R4  3.0  7.0   NaN

 

 

 

 

DataFrame의 행(row)과 열(column)을 선택할 때는 df.['xx'][0:2] 를 예를 들어 소개합니다.

 

 

In [42]: df

Out[42]:

     C1   C2    C3
R1  0.0  4.0   8.0
R2  1.0  5.0   9.0
R3  2.0  6.0  10.0
R4  3.0  7.0   NaN

 


# selecting column form DataFrame

In [43]: df['C1']

Out[43]:

R1    0.0
R2    1.0
R3    2.0
R4    3.0
Name: C1, dtype: float64


In [44]: df.C1

Out[44]:

R1    0.0
R2    1.0
R3    2.0
R4    3.0
Name: C1, dtype: float64

 

# selecting row from DataFrame

In [45]: df[0:2]

Out[45]:

     C1   C2   C3
R1  0.0  4.0  8.0
R2  1.0  5.0  9.0

 

# indexing 'column' and 'row' from DataFrame

In [46]: df['C1'][0:2]

Out[46]:

R1    0.0
R2    1.0
Name: C1, dtype: float64


In [47]: df.C1[0:2]

Out[47]:

R1    0.0
R2    1.0
Name: C1, dtype: float64

 

 

 

 

index label을 가지고 행(row) 선택할 때는 df.loc['xx'] 를 사용합니다.

 

 

# Select row by label : df.loc[label]

In [48]: df.loc['R1']

Out[48]:

C1    0.0
C2    4.0
C3    8.0
Name: R1, dtype: float64


In [49]: df.loc[['R1', 'R2']]

Out[49]:

     C1   C2   C3
R1  0.0  4.0  8.0
R2  1.0  5.0  9.0

 

 

 

 

index의 label 이 아니라 정수(integer)로 indexing을 하려면 df.iloc[int] 를 사용해야 합니다.  만약 df.loc[int]를 사용하면 TypeError 가 발생합니다.

 

 

# TypeError: cannot do label indexing on with these indexers [0] of <class 'int'>

In [50]: df.loc[0] # TypeError

TypeError: cannot do label indexing on <class 'pandas.indexes.base.Index'> with these indexers [0] of <class 'int'>

 

 

# Select row by interger location : df.iloc[loc]

In [51]: df.iloc[0]

Out[51]:

C1    0.0
C2    4.0
C3    8.0
Name: R1, dtype: float64


In [52]: df.iloc[0:2]

Out[52]:

     C1   C2   C3
R1  0.0  4.0  8.0
R2  1.0  5.0  9.0

 

 

 

 

DataFrame의 행(row) indexing할 때 df[0:2] 처럼 행의 범위를 ':'로 설정해주어도 됩니다.  df[0] 처럼 정수값을 지정하면 KeyError 납니다(이때는 df.iloc[0] 을 써야 함).

 

 

# KeyError: 0

In [53]: df[0]  # KeyError: 0

KeyError: 0

 

 

# Select rows : df[0:2]

In [54]: df[0:2]

Out[54]:

     C1   C2   C3
R1  0.0  4.0  8.0
R2  1.0  5.0  9.0

 

 

 

 

조건을 부여해서 열을 선택할 수도 있습니다.

 

 

# Select rows by boolean vector : df[bool_vec]

In [55]: df[df['C1'] <= 1.0]

Out[55]:

     C1   C2   C3
R1  0.0  4.0  8.0
R2  1.0  5.0  9.0

 

 

 

 

 

선택할 칼럼을 벡터 객체로 만들어 놓고, DataFrame에서 벡터 객체에 들어있는 칼럼만 선별해올 수도 있겠지요. 분석 프로세스를 자동화하려고 할 때 선행 분석 결과를 받아서 벡터 객체로 만들어 놓고, 이를 받아서 필요한 변수만 선별할 때 종종 사용하곤 합니다.

 


# Select columns by column vector : df[col_bool_vec]

In [56]: df_col_selector = ['C1', 'C2']


In [57]: df[df_col_selector]

Out[57]:

     C1   C2
R1  0.0  4.0
R2  1.0  5.0
R3  2.0  6.0
R4  3.0  7.0

 

 

 

많은 도움 되었기를 바랍니다.

 

 

 

 

 

 

 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 데이터 프레임, 튜플, 리스트를 특정한 기준에 따라서 정렬, 재배치하는 방법에 대해서 알아보겠습니다.

 

오름차순 혹은 내림차순으로 정렬을 한 후에 상위 n개 (or 하위 n개), 혹은 첫번째 행 (or 마지막 행) 을 선택해야할 필요가 있을 때 사용할 수 있는 method, function 입니다.

 

DataFrame, Tuple, List 정렬 순서대로 소개하겠습니다.

 

 - (1) DataFrame 정렬 : DataFrame.sort_values()

 

 - (2) Tuple 정렬 : sorted(tuple, key)

 

 - (3) List 정렬 : list.sort(), sorted(list)

 

* 참고: Numpy 배열 정렬 np.sort()http://rfriend.tistory.com/357

 

 

 

 

  (1) DataFrame 정렬 : DataFrame.sort_values()

 

먼저 필요한 모듈을 불러오고, 예제 DataFrame을 만들어보겠습니다.

 

 

In [1]: import pandas as pd


In [2]: personnel_df = pd.DataFrame({'sequence': [1, 3, 2],

   ...: 'name': ['park', 'lee', 'choi'],

   ...: 'age': [30, 20, 40]})


In [3]: personnel_df

Out[3]:

   age  name  sequence
0   30  park         1
1   20   lee         3
2   40  choi         2

 

 

 

 

(1-1) 'sequence' 열(by='sequence')을 기준으로 index(axis=0) 오름차순 정렬하기

 

 

# sorting index of DataFrame by a specific column : axis=0, columns

In [4]: personnel_df.sort_values(by=['sequence'], axis=0)

Out[4]:

   age  name  sequence
0
   30  park         1
2   40  choi         2
1
   20   lee          3

 

 

 

 

(1-2) 내림차순(descending)으로 정렬하기 : ascending=False

 

 

# sorting index of dataFrame in descending order : ascending=False

In [5]: personnel_df.sort_values(by=['sequence'], axis=0, ascending=False)

Out[5]:

   age  name  sequence
1   20   lee         3
2   40  choi         2
0   30  park         1

 

 

 

 

(1-3) 열 이름을 (알파벳 순서로) 정렬하기 :  axis=1

 

 

# sorting columns of DataFrame : axis=1

In [6]: personnel_df.sort(axis=1)

Out[6]:

   age  name  sequence
0   30  park         1
1   20   lee         3
2   40  choi         2

 

# sorting columns of DataFrame in descending order : axis=1, ascending=False

In [7]: personnel_df.sort(axis=1, ascending=False

Out[7]:

   sequence  name  age
0         1  park   30
1         3   lee   20
2         2  choi   40

 

 

 

 

(1-4) DataFrame 자체 내에서 정렬된 상태로 다시 저장하기 : inplace=True

 

 

In [8]: personnel_df

Out[8]:

age name sequence

0 30 park 1

1 20 lee 3

2 40 choi 2


# sorting DataFarme in-place : inplace=True

In [9]: personnel_df.sort_values(by=['sequence'], axis=0, inplace=True)


In [10]: personnel_df

Out[10]:

age name sequence

0 30 park 1

2 40 choi 2

1 20 lee 3

 

 

 

 

(1-5) 결측값을 처음에(na_position='first'), 혹은 마지막(na_position='last') 위치에 정렬하기

 

 

# putting NaN to DataFrame

In [11]: import numpy as np


In [12]: personnel_df = pd.DataFrame({'sequence': [1, 3, np.nan],

    ...: 'name': ['park', 'lee', 'choi'],

    ...: 'age': [30, 20, 40]})

    ...:


In [13]: personnel_df

Out[13]:

   age  name  sequence
0   30  park       1.0
1   20   lee       3.0
2   40  choi       NaN

 


# first puts NaNs at the beginning : na_position='first'

In [14]: personnel_df.sort_values(by=['sequence'], axis=0, na_position='first')

Out[14]:

   age  name  sequence
2   40  choi       NaN
0   30  park       1.0
1   20   lee       3.0

 


# last puts NaNs at the end : na_position='last'

In [15]: personnel_df.sort_values(by=['sequence'], axis=0, na_position='last')

Out[15]:

   age  name  sequence
0   30  park       1.0
1   20   lee       3.0
2   40  choi       NaN

 

 

 

 

  (2) Tuple 정렬하기 : sorted(tuple, key) method

 

 

# making a tuple

In [16]: personnel_tuple = [(1, 'park', 30),

    ...: (3, 'lee', 20),

    ...: (2, 'choi', 40)]


In [17]: personnel_tuple

Out[17]: [(1, 'park', 30), (3, 'lee', 20), (2, 'choi', 40)]

 


# use 'key' parameter to specify a function to be called on

# sort by sequence number

In [18]: sorted(personnel_tuple, key=lambda personnel: personnel[0])

Out[18]: [(1, 'park', 30), (2, 'choi', 40), (3, 'lee', 20)]


# sort by name

In [19]: sorted(personnel_tuple, key=lambda personnel: personnel[1])

Out[19]: [(2, 'choi', 40), (3, 'lee', 20), (1, 'park', 30)]

 

# sort by age

In [20]: sorted(personnel_tuple, key=lambda personnel: personnel[2])

Out[20]: [(3, 'lee', 20), (1, 'park', 30), (2, 'choi', 40)]

 

 

 

내림차순(descending order)으로 정렬하고 싶으면 'reverse=True' 옵션을 설정해주면 됩니다.

 

 

# sorting tuple in descending order by age : reverse=True

In [21]: sorted(personnel_tuple, reverse=True, key=lambda personnel: personnel[2])

Out[21]: [(2, 'choi', 40), (1, 'park', 30), (3, 'lee', 20)]

 

 

 

 

  (3) List 정렬하기 : sorted(list), or list.sort()

 

 

 

# making a list

In [23]: my_list = [0, 1, 2, 3, 4, 9, 8, 7, 6, 5]

 


# (1) sorting a list : sort(list) function

In [24]: sorted(my_list)

Out[24]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

 

# (2) sorting a list : list.sort() method

In [25]: my_list.sort()


In [26]: my_list

Out[26]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 


# sorting a list in descending order : reverse=True

In [27]: sorted(my_list, reverse=True)

Out[27]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


In [28]: my_list.sort(reverse=True)


In [29]: my_list

Out[29]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

 

 

 

 

많은 도움 되었기를 바랍니다.

 

 

728x90
반응형
Posted by Rfriend
,

분석을 하다 보면 원본 데이터의 구조가 분석 기법에 맞지 않아서 행과 열의 위치를 바꾼다거나, 특정 요인에 따라 집계를 해서 구조를 바꿔주어야 하는 경우가 있습니다.

 

재구조화(reshaping data)를 위해 사용할 수 있는 Python pandas의 함수들로 아래와 같이 다양한 함수가 있습니다. 

 

 - (1) pivot(), pd.pivot_table()

 - (2) stack(), unstack()

 - (3) melt()

 - (4) wide_to_long()

 - (5) pd.crosstab() 

 

 

이번 포스팅에서는 마지막으로 범주형 변수로 되어있는 요인(factors)별로 교차분석(cross tabulations) 해서, 행, 열 요인 기준 별로 빈도를 세어서 도수분포표(frequency table), 교차표(contingency table) 를 만들어주는 pd.crosstab() 에 대해서 알아보겠습니다.

 

 

 

 

 

먼저 필요한 모듈을 불러오고, 예제로 사용할 (범주형 요인 변수를 가지고 있는) 간단한 데이터셋을 생성해보겠습니다.

 

 

In [1]: import pandas as pd


In [2]: from pandas import DataFrame


In [3]: data = DataFrame({'id': ['id1', 'id1', 'id1', 'id2', 'id2', 'id3'],

   ...: 'fac_1': ['a', 'a', 'a', 'b', 'b', 'b'],

   ...: 'fac_2': ['d', 'd', 'd', 'c', 'c', 'd']})


In [4]: data

Out[4]:

    fac_1   fac_2    id
0     a       d       id1
1     a       d       id1
2     a       d       id1
3     b       c       id2
4     b       c       id2
5     b       d       id3

 

 

 

 

  (1) 교차표(contingency table, frequency table) 만들기 : pd.crosstab(index, columns)

 

pd.crosstab()의 행과 열 위치에는 array 형식의 데이터가 들어갑니다

 

 

# cross tabulations using pd.crosstab => contingency table

In [5]: pd.crosstab(data.fac_1, data.fac_2)

Out[5]:
fac_2  c  d
fac_1     
a      0  3
b      2  1

 

In [6]: pd.crosstab(data.id, data.fac_1)

Out[6]: 
fac_1  a  b
id        
id1    3  0
id2    0  2
id3    0  1

 

In [7]: pd.crosstab(data.id, data.fac_2)

Out[7]:
fac_2  c  d
id        
id1    0  3
id2    2  0
id3    0  1

 

 

 

 

  (2) Multi-index, Multi-level로 교차표 만들기 : pd.crosstab([id1, id2], [col1, col2])

 

 

# cross tabulations using pd.crosstab with Multi-level columns

In [8]: pd.crosstab(data.id, [data.fac_1, data.fac_2])

Out[8]:

fac_1  a  b  
fac_2  d  c  d
id           
id1    3  0  0
id2    0  2  0
id3    0  0  1


In [9]: pd.crosstab([data.fac_1, data.fac_2], data.id)

Out[9]:

id           id1  id2  id3
fac_1 fac_2              
a     d        3    0    0
b     c        0    2    0
      d        0    0    1

 

 

 

 

  (3) 교차표의 행 이름, 열 이름 부여 : pd.crosstab(rownames=['xx'], colnames=['aa'])

 

 

# pd.crosstab(rownames, colnames) : giving rownames, colnames

In [10]: pd.crosstab(data.id, [data.fac_1, data.fac_2],

    ...: rownames=['id_num'],

    ...: colnames=['a_b', 'c_d'])

Out[10]:

a_b     a  b  
c_d     d  c  d
id_num        
id1     3  0  0
id2     0  2  0
id3     0  0  1

 

 

 

 

  (4) 교차표의 행 합, 열 합 추가하기 : pd.crosstab(margins=True)

 

 

# pd.crosstab(margins=True) : adding row/column margins

In [11]: pd.crosstab(data.id, [data.fac_1, data.fac_2],

    ...: margins=True)

Out[11]:

fac_1  a  b    All
fac_2  d  c  d   
id               
id1    3  0  0   3
id2    0  2  0   2
id3    0  0  1   1
All    3  2  1   6

 

 

 

 

 

  (5) 구성비율로 교차표 만들기 : pd.crosstab(normalize=True)

 

# pd.corsstab(normalize=True)
# : Normalize by dividing all values by the sum of values

In [12]: pd.crosstab(data.id, [data.fac_1, data.fac_2],

    ...: normalize=True)

Out[12]:

fac_1    a         b         
fac_2    d         c         d
id                           
id1    0.5  0.000000  0.000000
id2    0.0  0.333333  0.000000
id3    0.0  0.000000  0.166667

 

 

 

 

이상으로 pd.crosstab() 을 이용한 교차표 구하기를 마치겠습니다. 

 

 

교차표는 R이나 SPSS가 깔끔하게 결과를 제시해주는 것 같고요, R이 분석가가 설정할 수 있는 옵션이 조금 더 다양하므로 입맛에 맞게 교차분석도 하고 카이제곱검정도 하고 싶은 분은 아래 링크되어 있는 포스팅을 참고하세요. 

 

 

 

많은 도움이 되었기를 바랍니다.  

 

 

728x90
반응형
Posted by Rfriend
,

분석을 하다 보면 원본 데이터의 구조가 분석 기법에 맞지 않아서 행과 열의 위치를 바꾼다거나, 특정 요인에 따라 집계를 해서 구조를 바꿔주어야 하는 경우가 있습니다.

 

재구조화(reshaping data)를 위해 사용할 수 있는 Python pandas의 함수들에 대해서 아래의 순서대로 나누어서 소개해보겠습니다.

 

 - (1) pivot(), pd.pivot_table()

 - (2) stack(), unstack()

 - (3) melt()

 - (4) wide_to_long()

 - (5) pd.crosstab() 

 

 

이번 포스팅에서는 pd.wide_to_long() 에 대해서 알아보겠습니다.

 

필요한 모듈을 불러오고, 실습에 필요한 간단한 예제 데이터셋을 만들어보겠습니다.

 

 

# importing libraries

In [1]: import numpy as np


In [2]: import pandas as pd


In [3]: from pandas import DataFrame


# setting random seed number

In [4]: np.random.seed(10)


# making an example 'wide' DataFrame

In [5]: data_wide = pd.DataFrame({"C1prd1" : {0 : "a", 1 : "b", 2 : "c"},

   ...: "C1prd2" : {0 : "d", 1 : "e", 2 : "f"},

   ...: "C2prd1" : {0 : 2.5, 1 : 1.2, 2 : .7},

   ...: "C2prd2" : {0 : 3.2, 1 : 1.3, 2 : .1},

   ...: "value" : dict(zip(range(3), np.random.randn(3)))

   ...: })

   ...:


In [6]: data_wide["seq_no"] = data_wide.index


In [7]: data_wide

Out[7]:

     C1prd1 C1prd2  C2prd1  C2prd2     value      seq_no
0       a         d         2.5       3.2      1.331587       0
1       b         e         1.2       1.3      0.715279       1
2       c          f         0.7       0.1     -1.545400       2

 

 

 

 

이제 pd.wide_to_long() 함수를 써서 데이터를 재구조화 해보겠습니다.

 

wide_to_long()은 pivot() 이나 stack() 과는 다르게 "칼럼 이름의 앞부분"과 나머지 "칼럼 이름의 뒷부분"을 구분해서, 칼럼 이름의 앞부분을 칼럼 이름으로, 칼럼 이름의 나머지 뒷부분을 행(row)의 원소로 해서 세로로 길게(long~) 쌓아 줍니다.  말로 설명해주기가 참 힘든데요, 아래의 wide_to_long() 적용 전, 후의 변화 이미지를 참고하시기 바랍니다.

 

제가 R, SAS, SPSS 다 써봤는데요, Python의 pd.wide_to_long() 함수 같은거는 본 적이 없습니다. 좀 생소하고, 처음 봤을 때 한눈에 잘 안들어왔던 유형의 데이터 재구조화 함수예요. 

 

 

 

pd.widt_to_long() 함수를 한번 사용해서 가로로 넓은 데이터(wide~)를 세로로 길게(long~) 재구조화 해보겠습니다.

 

 

  (1) pd.wide_to_long(data, ["col_prefix_1", "col_prefix_2"], i="idx_1", j="idx_2")

 

 

# reshaping a 'wide' DataFrame to a 'long' DataFrame

In [8]: data_long = pd.wide_to_long(data_wide, ["C1", "C2"], i="seq_no", j="prd")


In [9]: data_long

Out[9]:

                     value    C1    C2
seq_no prd                 
0        prd1  1.331587      2.5
1        prd1  0.715279   b     1.2
2        prd1 -1.545400   c     0.7
0        prd2  1.331587      3.2
1        prd2  0.715279   e     1.3
2        prd2 -1.545400   f     0.1

 

 

 

 

  (2) pd.wide_to_long()에 의한 index, columns 변화 비교

 

 

# data_wide (original data set) : index, columns

In [10]: data_wide.index

Out[10]: Int64Index([0, 1, 2], dtype='int64')


In [11]: data_wide.columns

Out[11]: Index(['C1prd1', 'C1prd2', 'C2prd1', 'C2prd2', 'value', 'seq_no'], dtype='object')

 


# data_long (reshaped data set) : index, columns

In [12]: data_long.index

Out[12]:

MultiIndex(levels=[[0, 1, 2], ['prd1', 'prd2']],

labels=[[0, 1, 2, 0, 1, 2], [0, 0, 0, 1, 1, 1]],

names=['seq_no', 'type'])


In [13]: data_long.columns

Out[13]: Index(['value', 'C1', 'C2'], dtype='object')

 

 

 

이상으로 pd.wide_to_long() 을 이용한 데이터 재구조화 소개를 마치겠습니다.

 

다음번 포스팅에서는 pd.crosstab() 에 대해서 알아보겠습니다.

 

많은 도움 되었기를 바랍니다.

 

 

728x90
반응형
Posted by Rfriend
,

데이터 재구조화(reshaping data)를 위해 사용할 수 있는 Python pandas의 함수들에 대해서 아래의 순서대로 나누어서 소개해보겠습니다.
 
 - (1) pivot(), pd.pivot_table()
 - (2) stack(), unstack()
 - (3) melt()

 - (4) wide_to_long()
 - (5) pd.crosstab() 
 
 
이번 포스팅에서는 세번째로 pd.melt() 사용법에 대해서 알아보겠습니다.

 

R 사용자라면 reshape package의 melt(), cast() 함수를 생각하면 쉽게 이해할 수 있을 것입니다. melt()는 pivot_table()과 함께 데이터 전처리 단계에서 자주 사용되곤 합니다.

 

melt() 는 ID 변수를 기준으로 원래 데이터셋에 있던 여러개의 칼럼 이름을 'variable' 칼럼에 위에서 아래로 길게 쌓아놓고, 'value' 칼럼에 ID와 variable에 해당하는 값을 넣어주는 식으로 데이터를 재구조화합니다.  말로 설명하자니 좀 어려운데요, 아래의 melt() 적용 전, 후의 이미지를 참고하시기 바랍니다.

 

 

 

 

필요한 라이브러리를 불러오고, 예제로 사용할 간단한 DataFrame을 만들어보겠습니다.

 

 

# importing libraries

In [1]: import numpy as np


In [2]: import pandas as pd


In [3]: from pandas import DataFrame

 

# making an example DataFrame

In [4]: data = DataFrame({'cust_ID' : ['C_001', 'C_001', 'C_002', 'C_002'],

   ...: 'prd_CD' : ['P_001', 'P_002', 'P_001', 'P_002'],

   ...: 'pch_cnt' : [1, 2, 3, 4],

   ...: 'pch_amt' : [100, 200, 300, 400]})

   ...:


In [5]: data

Out[5]:

  cust_ID  pch_amt  pch_cnt prd_CD
0   C_001      100        1  P_001
1   C_001      200        2  P_002
2   C_002      300        3  P_001
3   C_002      400        4  P_002

 

 

 

 

  (1) pd.melt(data, id_vars=['id1', 'id2', ...]) 를 사용한 데이터 재구조화

 

 

# melt()

In [6]: pd.melt(data, id_vars=['cust_ID', 'prd_CD'])

Out[6]:

   cust_ID prd_CD variable     value
0   C_001  P_001  pch_amt    100
1   C_001  P_002  pch_amt    200
2   C_002  P_001  pch_amt    300
3   C_002  P_002  pch_amt    400
4   C_001  P_001  pch_cnt      1
5   C_001  P_002  pch_cnt      2
6   C_002  P_001  pch_cnt      3
7   C_002  P_002  pch_cnt      4

 

 

 

 (2) pd.melt() 의 variable 이름, value 이름 부여하기 : var_name, value_name

 

 

# # melt : assigning name of variable and value

In [7]: pd.melt(data, id_vars=['cust_ID', 'prd_CD'],

   ...: var_name='pch_CD', value_name='pch_value')

Out[7]:

  cust_ID  prd_CD  pch_CD      pch_value
0   C_001  P_001   pch_amt        100
1   C_001  P_002   pch_amt        200
2   C_002  P_001   pch_amt        300
3   C_002  P_002   pch_amt        400
4   C_001  P_001   pch_cnt          1
5   C_001  P_002   pch_cnt          2
6   C_002  P_001   pch_cnt          3
7   C_002  P_002   pch_cnt          4

 

 

 

 

  (3) data vs. pd.melt() vs. pd.pivot_table() 비교해보기

 

melt()와 pivot_table() 이 비슷한거 같은데.... 뭔가 다른거 같기도 하고... 왜 비슷한것들을 여러개 만들어놔서 사람을 헷갈리게 하는 것일까 의아할 것 같습니다.

 

아래에 똑같은 data에 대해서 melt()와 pivot_table() 을 적용해보았습니다.  melt()와 pivot_table()을 적용하고 난 이후의 index와 columns 을 유심히 살펴보시기 바랍니다.  melt()는 ID가 칼럼으로 존재하는 반면에, pivot_table()은 ID가 index로 들어갔습니다.

 

 

# comparison among (a) data vs. (b) pd.melt() vs. pd.pivot_table()

 

# (a) data

In [8]: data

Out[8]:

  cust_ID  pch_amt  pch_cnt prd_CD
0   C_001      100        1  P_001
1   C_001      200        2  P_002
2   C_002      300        3  P_001
3   C_002      400        4  P_002

 


# (b) melt()

In [9]: data_melt = pd.melt(data, id_vars=['cust_ID', 'prd_CD'],

   ...: var_name='pch_CD', value_name='pch_value')


In [10]: data_melt

Out[10]:

  cust_ID prd_CD   pch_CD  pch_value
0   C_001  P_001  pch_amt        100
1   C_001  P_002  pch_amt        200
2   C_002  P_001  pch_amt        300
3   C_002  P_002  pch_amt        400
4   C_001  P_001  pch_cnt          1
5   C_001  P_002  pch_cnt          2
6   C_002  P_001  pch_cnt          3
7   C_002  P_002  pch_cnt          4


In [11]: data_melt.index

Out[11]: RangeIndex(start=0, stop=8, step=1)


In [12]: data_melt.columns

Out[12]: Index(['cust_ID', 'prd_CD', 'pch_CD', 'pch_value'], dtype='object')

 


# (c) pd.pivot_table()

In [13]: data_melt_pivot = pd.pivot_table(data_melt, index=['cust_ID', 'prd_CD'],

    ...: columns='pch_CD', values='pch_value',

    ...: aggfunc=np.mean)


In [14]: data_melt_pivot

Out[14]:

pch_CD             pch_amt   pch_cnt
cust_ID prd_CD                 
C_001   P_001       100        1
           P_002       200        2
C_002   P_001       300        3
           P_002       400        4


In [15]: data_melt_pivot.index

Out[15]:

MultiIndex(levels=[['C_001', 'C_002'], ['P_001', 'P_002']],

labels=[[0, 0, 1, 1], [0, 1, 0, 1]],

names=['cust_ID', 'prd_CD'])


In [16]: data_melt_pivot.columns

Out[16]: Index(['pch_amt', 'pch_cnt'], dtype='object', name='pch_CD')

 

 

 

이상으로 Pytho pandas의 melt() 함수를 가지고 데이터 재구조화하는 방법에 대한 소개를 마치겠습니다.

 

다음번 포스팅에서는 wide_to_long() 함수에 대해서 알아보겠습니다.

 

 

 

728x90
반응형
Posted by Rfriend
,