Python의 Dictionary는 {Key: Value}의 쌍(pair)로 이루어진 자료형입니다. 

이번 포스팅에서는 Python Dictionary 를 분할하여 새로운 Dictionary로 만드는 방법을 소개하겠습니다. 

 

(1) Dictionary 의 특정 값을 가진 sub Dictionary 만들기

(2) Dictionary 를 특정 비율로 분할하기

 

 

먼저 예제로 사용할 Dictionary를 만들어보겠습니다. key 는 영어 알파벳이고, value 는 정수 [0, 1, 2] 중에서 무작위로 생성해서 {key: value} 쌍으로 이루어진 Dictionary 입니다. 

 

# Sample Dictionary
import string
import numpy as np
np.random.seed(1004) # for reproducibility

k = list(string.ascii_lowercase)
v = np.random.randint(3, size=len(k))

my_dict = {k: v for k, v in zip(k, v)}

print(my_dict)

# {'a': 2, 'b': 1, 'c': 2, 'd': 0, 'e': 1, 'f': 2, 'g': 1, 
#  'h': 1, 'i': 0, 'j': 0, 'k': 0, 'l': 0, 'm': 0, 'n': 2, 
#  'o': 2, 'p': 0, 'q': 2, 'r': 0, 's': 2, 't': 1, 'u': 0, 
#  'v': 1, 'w': 0, 'x': 2, 'y': 0, 'z': 2}

 

 

 

(1) Dictionary 의 특정 값을 가진 sub Dictionary 만들기

 

먼저 my_dict 내 원소의 value 가 각각 0, 1, 2 인 sub Dictionary  를 만들어보겠습니다. 

my_dict.items() 로 Dictionary 내 원소 값을 불러오고, 조건절이 있는 list comprehension 을 이용하였으며, for loop 순환문을 사용해도 됩니다. 

 

# (1) Split a Dictionary by each value categories of 0, 1, 2
dict_0 = {k: v for k, v in my_dict.items() if v == 0}
dict_1 = {k: v for k, v in my_dict.items() if v == 1}
dict_2 = {k: v for k, v in my_dict.items() if v == 2}

print('Dict 0:', dict_0)
print('Dict 1:', dict_1)
print('Dict 2:', dict_2)

# Dict 0: {'d': 0, 'i': 0, 'j': 0, 'k': 0, 'l': 0, 'm': 0, 'p': 0, 'r': 0, 'u': 0, 'w': 0, 'y': 0}
# Dict 1: {'b': 1, 'e': 1, 'g': 1, 'h': 1, 't': 1, 'v': 1}
# Dict 2: {'a': 2, 'c': 2, 'f': 2, 'n': 2, 'o': 2, 'q': 2, 's': 2, 'x': 2, 'z': 2}

 

 

 

(2) Dictionary 를 특정 비율로 분할하기

 

Split a Dictionary by proportions

 

이제 위에서 생성한 sub Dictionary를 먼저 무작위로 순서를 재정렬한 후에,  [training : validation : test] = [0.6 : 0.2 : 0.2] 의 비율로 분할을 해보겠습니다. 

 

list(dict_k.keys()) 로 각 sub Dictionary 의 key 값을 리스트로 만든 후에, random.shuffle(keys_list) 로 key 값을 무작위로 순서를 재정렬해주었습니다. 

 

그 후에 [train:validation:test] = [0.6:0.2:0.2] 의 비율에 해당하는 각 sub Dictionary의 원소값의 개수를 계산한 후에, 이 원소 개수만큼 keys_list 에서 key 값 리스트를 indexing 해 옵니다.

 

그리고 마지막으로 list comprehension을 이용해서 train, validation, test set 별 key 해당하는 value 를 가져와서 {key: value} 쌍으로 train/validation/test set의 각 Dictionary를 만들어주면 됩니다. 

 

# (2) Split each Dictionary into training set 60%, validation 20%, test set 20% randomly
def split_dict(dict_k, train_r=0.6, val_r=0.2, verbose=False):
    import random
    random.seed(1004) 

    keys_list = list(dict_k.keys())

    # randomize the order of the keys
    random.shuffle(keys_list)

    # numbers per train, validation, and test set
    num_train = int(len(keys_list) * train_r)
    num_val = int(len(keys_list) * val_r)

    # split kyes
    keys_train = keys_list[:num_train] # 60%
    keys_val = keys_list[num_train:(num_train+num_val)] # 20%
    keys_test = keys_list[(num_train+num_val):] # 20% = 1 - train_ratio - val_ratio

    # split a Dictionary
    dict_k_train = {k: dict_k[k] for k in keys_train}
    dict_k_val   = {k: dict_k[k] for k in keys_val}
    dict_k_test  = {k: dict_k[k] for k in keys_test}
    
    if verbose:
        print('Keys List:', keys_list)
        print('---' * 20)
        print('Training set:', dict_k_train)
        print('Validation set:', dict_k_val)
        print('Test set:', dict_k_test)
    
    return dict_k_train, dict_k_val, dict_k_test

 

 

 

실제로 dict_0, dict_1, dict_2 의 각 sub Dictionary에 위에서 정의한 사용자 정의 함수 split_dict() 함수를 적용해보겠습니다. 

 

## (a) split dict_0
dict_0_train, dict_0_val, dict_0_test = split_dict(
    dict_0, 
    train_r=0.6, 
    val_r=0.2, 
    verbose=True
)

# Keys List: ['m', 'r', 'l', 'd', 'j', 'w', 'y', 'k', 'u', 'i', 'p']
# ------------------------------------------------------------
# Training set of Dict 0: {'m': 0, 'r': 0, 'l': 0, 'd': 0, 'j': 0, 'w': 0}
# Validation set of Dict 0: {'y': 0, 'k': 0}
# Test set of Dict 0: {'u': 0, 'i': 0, 'p': 0}


## (b) split dict_1
dict_1_train, dict_1_val, dict_1_test = split_dict(
    dict_1, 
    train_r=0.6, 
    val_r=0.2, 
    verbose=True
)

# Keys List: ['g', 'v', 't', 'e', 'b', 'h']
# ------------------------------------------------------------
# Training set: {'g': 1, 'v': 1, 't': 1}
# Validation set: {'e': 1}
# Test set: {'b': 1, 'h': 1}


## (c) split dict_2
dict_2_train, dict_2_val, dict_2_test = split_dict(
    dict_2, 
    train_r=0.6, 
    val_r=0.2, 
    verbose=True
)

# Keys List: ['f', 'n', 'a', 'x', 'z', 'o', 'q', 'c', 's']
# ------------------------------------------------------------
# Training set of Dict 0: {'m': 0, 'r': 0, 'l': 0, 'd': 0, 'j': 0, 'w': 0}
# Validation set of Dict 0: {'y': 0, 'k': 0}
# Test set of Dict 0: {'u': 0, 'i': 0, 'p': 0}

 

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python의 Dictionary로 Key: Value 매핑하여 문자열을 변경해주는 replace() 함수를 사용하여 SQL query 코드의 여러개의 문자열을 변경하는 방법을 소개하겠습니다. 

코드가 길고 동일한 특정 변수나 테이블 이름이 여러번 나오는 경우, 수작업으로 일일이 하나씩 찾아가면서 변수나 테이블 이름을 변경하다보면 사람의 실수(human error)가 발생할 위험이 큽니다.  이럴 때 Dictionary에 (변경 전 : 변경 후) 매핑을 관리하고 컴퓨터에게 코드 변경을 시킬 수 있다면 사람의 실수를 예방하는데 도움이 될 것입니다. 

 

먼저, 예제로 사용할 SQL query와 Key(Before, 변경 전): Value(After, 변경 후) 를 매핑한 Dictionary 를 만들어보겠습니다. 

 

## key(Before): value(After) mapping dictionary
map_dict = {
    'X1': '"변수1"', # Key(Before): Value(After)
    'X2': '"변수2"', 
    'X3': '"변수3"',
    'MYTABLE': 'TEST_TABLE'
}


sql_query = "select \nx1, x2, x3 \nfrom mytable \nwhere x2 > 10 \nlimit 10;"

print(sql_query)
# select 
# x1, x2, x3 
# from mytable 
# where x2 > 10 
# limit 10;

 

 

 

아래에는 여러개의 줄(lines)을 가지는 문자열을 하나의 줄(line)로 나누어주는 splitlines() 메소드와, Dictionary의 Key, Value를 쌍으로 반환해주는 items() 메소드를 소개하였습니다. 

 

## splitlines()
for l in sql_query.splitlines():
    print(l)

# select 
# x1, x2, x3 
# from mytable 
# where x2 > 10 
# limit 10;



## replace(a, b) method convert a string 'a' with 'b'
s = 'Hello Python World.'
s.replace('Hello', 'Hi')

# 'Hi Python World.'



# dictionary.items() ==> returns key, value
for k, v in map_dict.items():
    print(k, ':', v)

# X1 : "변수1"
# X2 : "변수2"
# X3 : "변수3"
# MYTABLE : TEST_TABLE

 

 

 

위에서 기본적인 splitlines(), replace(), items() 메소드에 대한 사용법을 알았으니, 이제 이를 엮어서 코드에 있는 여러개의 특정 변수나 테이블 이름을 Dictionary(변경 전 이름 Key: 변경 후 이름 Value 매핑) 에서 가져와서 replace() 메소드로 변경해주는 사용자 정의함수를 만들어보겠습니다. 

 

## User Defined Function for converting codes 
## using replace() function and dictionary(Before: After mapping)
def code_converter(codes_old, map_dict):
    # blank string to save the converted codes
    codes_converted = ''
    
    # converting codes using replace() function and dictionary(Before: After mapping)
    for code in codes_old.splitlines():
        for before, after in map_dict.items():
            code = code.upper().replace(before, after)
            
        codes_converted = codes_converted + code + '\n'
        
    return codes_converted
    

## executing the UDF above
sql_query_new = code_converter(sql_query, map_dict)


print(sql_query_new)
# SELECT 
# "변수1", "변수2", "변수3" 
# FROM TEST_TABLE 
# WHERE "변수2" > 10 
# LIMIT 10;

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 파이썬의 5가지 자료 구조, 변수 유형에 대해서 간략하게 알아보겠습니다. 


몇 년을 SAS 사용하다가 R 을 배우기 시작했을 때 R의 자료 구조가 좀 낯설었는데요, R 사용하다가 Python 배우기 시작하니 또 좀 생소하더군요. 처음엔 낯설어도 자꾸 사용하다보면 또 금새 익숙해지니 너무 부담갖지는 마시구요.


무슨 언어를 사용하던지 자료 유형(Data Type)에 대해서 정확하게 알고 있는 것이 정말, 진짜로, 억수로, 무지막지하게 중요합니다.  가장 기본이 되는 것이라서 정확하게 숙지를 하고 있어야 합니다. 


파이썬의 자료 구조, 변수 유형에는 수(Number), 문자열(String), 리스트(List), 튜플(Tuple), 사전(Dictionary)의 5가지 유형이 있습니다.  이번 포스팅에서는 수(Number)와 문자열(String)을 먼저 살펴보겠습니다. 



[ 파이썬의 자료/변수 유형 (Python's 5 Data Types, Variable Types) ]





 (1) 수 (Numbers)

: 정수(integer), 실수(real number), 복소수 (complex number)


먼저 수 (Number) 인데요, 더 세부적으로 구분해보자면 파이썬이 지원하는 수에는 정수(Integer), 실수(Real Number), 복소수(Complex Nuber) 의 3가지가 있습니다.


(1-1) 정수 (Integer)


파이썬은 메모리가 허용하는 선에서 무한대의 정수를 사용할 수 있습니다.  

type() 함수로 자료유형을 확인할 수 있습니다. 


#%% (1) Numbers # (1-1) int : signed integers


In [1]: num_int = 100


In [2]: type(num_int)

Out[2]: int 




참고로, 파이썬이 제공하는 수에 대한 산술 연산자(arithmetic operators)에는 아래의 7가지가 있습니다.  연산자(operator) 기호는 기억해두면 편할텐데요, 나누기(division), 나눗셈의 몫(floor division), 나눗셈의 나머지(modulus) 가 항상 헷갈립니다. ^^;


연산자 (operator)

 설명

예 

 +

 더하기 (addition)

 5 + 2 = 7

 -

 빼기 (subtraction)

5 - 2 = 3 

 곱하기 (multiplication)

5 * 2 = 10

 /

나누기 (division) 

 5 / 2 = 2.5

 //

나눗셈의 몫 (floor division) 

 5 // 2 = 2

 %

나눗셈의 나머지 (modulus) 

5 % 2 = 1 

 **

지수 (exponent) 

5 ** 2 = 25



파이썬은 수를 2진수, 8진수, 16진수로 변환할 수 있는 함수를 제공합니다. 참고로, 컴퓨터가 정보를 처리하는 가장 작은 단위가 '0'과 '1'로 구성된 비트(bit) 이고, 비트가 8개 모여서 바이트(byte)가 되는데요, 1 바이트로는 0 ~ 255 (2^8 -1 개) 개의 수를 표현할 수 있습니다.


아래 표에 10진수 10을 각 2진수, 8진수, 16진수로 변환해 보았습니다.


진법별로 변환해주는 함수 (function)

 접두사 (prefix)

예 

2진수(Binary number)로 변환: bin()

 0b

In [26]: bin(10)

Out[26]: '0b1010'

8진수(Octal number)로 변환: oct()

 0o

 In [27]: oct(10)

Out[27]: '0o12'

 16진수(Hexadecimal number)로 변환: hex()

 0x

 In [28]: hex(10)

Out[28]: '0xa'



(1-2) 실수 (Real Number): 부동 소수형


파이썬은 실수를 지원하기 위해 소수점이 있는 부동 소수형(floating point real values)을 제공합니다. 



# (1-2) float : floating point arithmetic

In [3]: num_float = 12.345


In [4]: type(num_float)

Out[4]: float 




파이썬이 정수는 메모리가 허용하는 한 무한대로 저장, 처리할 수 있다고 했는데요, 부동 소수형은 저장공간을 효율적으로 사용하기 위해 8 바이트만 사용해서 소수를 저장, 표현하므로 정도밀에 한계가 있습니다. 부동 소수형 수를 가지고 계산을 하다보면 끝자리 수가 미묘하게 예상했던 것과 다른 결과가 나오는 경우가 있으므로 정밀한 계산을 요구하는 경우에는 주의를 해야 합니다. 


수학에서 가장 많이 사용되는 무리수, 무한소수인 원주율(ratio of circumference of circle to its diameter ""3.141592653589793238462...)과 자연상수(The mathematical constant "e", 2.71828182845904523536...)를 파이썬의 math 모듈을 사용해서 표현해 보겠습니다. 부동 소수형으로 표현되어 자리 수가 제한되어 있음을 확인할 수 있습니다. 



In [5]: import math


In [6]: math.pi

Out[6]: 3.141592653589793


In [7]: math.e

Out[7]: 2.718281828459045 




(1-3) 복소수 (Complex Number): 실수(Real Number) + 허수(Imaginary Number: j)


복소수는 실수(real number)와 허수(imaginary number, i)로 구성된 수입니다. 고등학교 때 배워서 기억이 좀 가물가물할 수도 있는데요, (a, b는 실수, i는 허수) 형태로 표현하고, 이때 허수 i 는 인 수입니다. 


파이썬에서는 허수를 i로 표기하는 대신에 j 로 표기합니다. 



# (1-4) complex : complex numbers

In [8]: num_complex = 3 + 0.45j


In [9]: type(num_complex)

Out[9]: complex


In [10]: num_complex.real

Out[10]: 3.0


In [11]: num_complex.imag

Out[11]: 0.45




복소수도 산술연산을 할 수 있는데요, 아래에 덧셈(+) 연산 예를 들어보았습니다. 



In [12]: num_complex_2 = num_complex + (1 + 2j)


In [13]: num_complex_2

Out[13]: (4+2.45j)

 

# delete number objects

In [14]: del num_int, num_float, num_complex, num_complex_2





 (2) 문자열 (String) 


(2-1) 문자열 생성 : ' ', " ", ''' ''', """ """


파이썬이 제공하는 자료형의 두번째로는 문자들이 가지런히 늘어서 있는 집합인 문자열(String)이 있습니다. 작은 따옴표('xx')나 큰 따옴표 ("xx")로 감싸서 표현합니다.



In [14]: str_1 = 'Hello World'


In [15]: str_1

Out[24]: 'Hello World'


In [16]: type(str_1)

Out[16]: str 




줄을 바꾸어서 여러개의 줄로 문자열을 표현해야 하는 경우에는 작은 따옴표 3개('''xx''') 또는 큰 따옴표 3개(""xx""")를 이용해서 표현합니다. 가령, 여러 줄의 SQL query를 DB connect해서 사용하는 경우에 작은 따옴표 3개를 사용하면 되겠습니다.



In [17]: mysql_Query = """SELECT var1, count(*) as cnt

    ...: FROM mytable

    ...: WHERE var1 = 'aaa'

    ...: GROUP BY var1

    ...: ORDER BY var1"""


In [18]: mysql_Query

Out[18]: "SELECT var1, count(*) as cnt\n FROM mytable\n WHERE var1 = 'aaa'\n GROUP BY var1\n ORDER BY var1"

 



(2-2) 문자열 분리 (slicing of a string) : [ ], [ : ]


문자열은 순서열(sequence) 형식으로서 [ ], [ : ] 와 같은 슬라이싱 연산자(slice operator) 를 사용해서 문자열의 일부분을 분리할 수 있습니다. R 사용하다가 파이썬의 슬라이싱 사용하려면 R과 파이썬이 슬라이싱 시작하는 위치, 끝나는 위치가 달라서 무척 헷갈립니다. ^^;


'Hello World' 문자열을 가지고 Python 으로 슬라이싱 하는 것과 동일한 결과를 얻기 위해서 R 로 subset() 함수를 사용해서 문자열 분리하는 예를 아래에 비교해보았습니다.


Python 

 

In [19]: a = 'Hello World'


In [20]: print(a)

Hello World


 > # subset of string using R

> a <- c('Hello World')

> a

[1] "Hello World"

# [] and [:] : slice operator with indexes starting at 0

# in the beginning of the string

In [21]: a[1]

Out[21]: 'e'


> substr(a, 2, 2)

[1] "e" 
 

In [22]: a[1:4]

Out[22]: 'ell'


 > substr(a, 2, 4)

[1] "ell"

 

In [23]: a[1:]

Out[23]: 'ello World'


 > substr(a, 2, nchar(str))

[1] "ello World"

 

In [24]: a[10]

Out[24]: 'd'


# final character of a string : string[-1]

In [25]: a[-1]

Out[25]: 'd'


> substr(a, 11, 11)

[1] "d"


 > substr(a, nchar(str), nchar(str))

[1] "d"


Python의 경우 string[-1] 이면 제일 마지막 위치에서 첫번째 문자를 슬라이싱 해오며, string[-2]이면 제일 마지막에서 두번째 문자를 슬라이싱 해옵니다. (R에서 indexing 할 때 '-1'을 사용하면 첫번째 객체를 삭제해버립니다. 완전 당황하는 수가 있어요. 겪어본 사람은 알지요... ㅋㅋ)



[ 문자열 슬라이싱의 시작과 끝 위치: Python vs. R 비교 ]




(2-3) 문자열 합치기 (concatenation of two strings) : +



# plus (+) sign: the string concatenation operator

In [26]: a + ' I Love You'

Out[26]: 'Hello World I Love You'

 




(2-4) 문자열 반복하기 (repetition of a string): *



# asterisk(*) : the repetition operator

In [27]: a*2

Out[27]: 'Hello WorldHello World'

 



다음번 포스팅에서는 문자열(string)이 자체적으로 가지고 있는 함수인 다양한 메소드(methods)에 대해서 알아보겠습니다.


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

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



728x90
반응형
Posted by Rfriend
,