이번 포스팅에서는 Python의 List Comprehension 에 대해서 알아보겠습니다.

(번역하기가 애매해서 영어 원문 그대로 사용하겠습니다)

 

1. List Comprehension 이란? 

 

Python의 List Comprehension 은 기존에 존재하는 List 에서 새로운 List 를 간결하게 생성하는 방법입니다.

 

List Comprehension Syntax 는 아래와 같습니다. 

new_list = [expression for item in iterable if condition == True]

 

 

 

간단한 예를 들어서 설명해보겠습니다.  아래에 6개의 도시를 원소로 가지는 List 가 있습니다. 첫글자가 "S"로 시작하는 도시명을 원소로 가지는 새로운 List를 만든다고 했을 때, for loop 순환문과 if 조건절을 사용하는 방법이 있습니다. 

 

city_list = ["Seoul", "New York", "London", "Shanghai", "Paris", "Tokyo"]

print(city_list)
# ['Seoul', 'New York', 'London', 'Shanghai', 'Paris', 'Tokyo']


## way 1: for loop and if conditional statement
city_s_1 = []

for city in city_list:
    if "S" in city:
        city_s_1.append(city)
        
        
print(city_s_1)
# ['Seoul', 'Shanghai']

 

 

첫글자가 "S"로 시작하는 도시명을 원소로 가지는 새로운 List를 만든다고 했을 때, List Comprehension 을 이용하면 아래와 같이 아주 간결하게 코드를 짤 수 있습니다. 

 

## way 2: List Comprehension
## [expression for item in iterable if condition == True]
city_s_2 = [city for city in city_list if "S" in city]

print(city_s_2)
# ['Seoul', 'Shanghai']

 

 

 

2. 내장 range() 함수와 조건절을 사용한 List Comprehension

 

Python의 iterable 자료형으로 str, list, tuple, dictionary, set, range 등이 있는데요, 아래 예에서는 그중에서 내장 range() 함수로 0~9까지의 정수를 반복적으로 생성해서, if 조건절을 사용해 짝수로 구성된 새로운 List 를 만들어보겠습니다. 

 

## range() 함수와 List Comprehension 으로 짝수 리스트 만들기
even_list = [i for i in range(10) if i%2 == 0]

print(even_list)
# [0, 2, 4, 6, 8]

 

 

 

3. if else 조건절을 사용해서 List Comprehension 만들기

 

if else 조건절을 List Comprehension 에서 사용할 때는 if else 조건절을 앞에 써주고, for loop 순환문을 뒤에 사용해줍니다. (* 위의 2번과 순서가 뒤바뀜에 주의)

 

## 짝수는 그대로, 홀수이면 99로 치환한 리스트
## if else 조건절이 앞에 있고, for 순환문이 뒤에 있음
if_else_list = [i if i%2 == 0 else 99 for i in range(10)]

print(if_else_list)
# [0, 99, 2, 99, 4, 99, 6, 99, 8, 99]

 

 

만약 for loop 순환문을 앞에 써주고 if else 조건절을 뒤에 써서 List Comprehension 을 시도하면 SyntaxError 가 납니다. 

 

## SyntaxError: invalid syntax
[i for i in range(10) if i%2 == 0 else 99] #SyntaxError

 

 

 

4. 2D List 에 대해 중첩된 순환문(Nested for loops)을 사용해서 List Comprehension 

 

4-1.  2D List 를 1D List 로 차원 줄이기 (flattening)

 

list_2d = [[11, 12], 
           [21, 22], 
           [31, 32], 
           [41, 42]
          ]
          
print(list_2d)
# [[11, 12], [21, 22], [31, 32], [41, 42]]


## flattening
## flattening
list_1d = [i for row in list_2d for i in row]

print(list_1d)
# [11, 12, 21, 22, 31, 32, 41, 42]

 

 

4-2. 2D List 를 전치(Transpose) 하기 

 

## Transpose
list_transpose = [[row[i] for row in list_2d] for i in range(2)]

print(list_transpose)
# [[11, 21, 31, 41], [12, 22, 32, 42]]

 

 

 

5. eval() 함수에 List Comprehension 실행하기

 

Python의 eval() 함수는 동적으로 문자열 표현식을 평가하여 실행합니다. (참고: https://rfriend.tistory.com/798 )

eval() 함수에 List Comprehension 을 문자열 표현식으로 넣어서 실행할 수 있습니다. 

 

## eval() 에 list comprehension 표현식(expression)사용 가능
str_list_comprehension = "[i for i in range(10) if i%2 == 0]"

eval(str_list_comprehension)
# [0, 2, 4, 6, 8]

 

 

하지만, 바로 위의 짝수 리스트를 만드는 List Comprehension 과 동일한 과업을 for loop 순환문과 if 조건절 statement 를 문자열로 만들어서 eval() 함수에 넣어 실행하려고 하면 SyntaxError 가 발생합니다. (eval() 함수는 expression 만 평가하여 실행가능하고, statement 는 평가 불가능함)

 

## eval()에 for loop 순환문과 if 조건절 statement 사용 불가
## SyntaxError: invalid syntax
str_for_if = """
new_list = []

for i in range(10):
    if i%2 == 0:
        new_list.append(i)
"""

eval(str_for_if) # SyntaxError: invalid syntax

 

 

 

6. List Comprehension 으로 새로운 Dict 만들기

 

str 자료형은 iterable 타입으로서, 아래처럼 List Comprehension 으로 각 단위문자 별로 쪼개서 새로운 List 로 만들 수 있습니다.  

 

text = "abcde"

print([s for s in text])
# ['a', 'b', 'c', 'd', 'e']

 

 

아래의 예는 range() 함수와 text 를 iterable 하면서 zip() 으로 정수와 각 단위문자를 짝을 이루어서 for loop 순환문으로 발생시키고, 이를  {Key: Value} 로 해서 새로운 Dict 자료형을 만든 것입니다.  

 

## list comprehension을 이용해서 dictionary 만들기
text = "abcde"

{k: v for k, v in zip(range(len(text)), text)}
# {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}

 

 

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

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

 

728x90
반응형
Posted by Rfriend
,

이번 포스티에서는 Python의 내장 함수인 eval() 함수에 대해서 소개하겠습니다. 

 

(1) Python의 eval() 함수 구문 이해 및 문자열 표현식 인풋을 eval() 함수에 사용하기

(2) eval() 함수의 잘못된 사용 예시 (SyntaxError) 

(3) compiled-code-based 인풋을 eval() 함수에 사용하기

 

 

python eval() function

 

(1) Python의 eval() 함수 구문 이해 및 문자열 표현식 인풋을 eval() 함수에 사용하기

 

Python 의 내장함수(built-in function)인 eval() 함수는 임의의 문자열 기반(string-based) 또는 컴파일된 코드 기반 (compiled-code-based) 인풋의 표현식(expressions)을 평가(evaluate)해서 실행해줍니다. 

 

문자열 기반의 표현식을 eval() 함수가 처리하는 순서는 아래와 같습니다. 

 

  (1-a) 문자열 기반 표현식을 파싱한다. (Parse a string-based expression)

  (1-b) 문자열을 파싱한 결과를 바이트코드로 컴파일한다. (Compile it to bytecode)

  (1-c) 파이썬 표현식으로 평가한다. (Evaluate it as a Python expression) 

  (1-d) 평가한 결과를 하나의 값으로 반환한다. (Return the result of the evaluation)

 

 

아래 예시는 문자열 기반 표현식 (string-based expressions) 으로 수학 계산식(math expressions)을 인풋으로 해서 eval() 메소드를 사용해 동적으로 평가하여 실행한 것입니다. 

 

## You can use the built-in Python eval() 
## to dynamically evaluate expressions 
## from a string-based or compiled-code-based input.

##-- eval() for a string-based input
##-- Math expressions
eval("2 + 6")
# 8

eval("10**2")
# 100

eval("sum([1, 2, 3, 4, 5])")
# 15


import math
eval("math.pi * pow(5, 2)")
# 78.53981633974483

 

 

 

eval() 함수는 문자열 표현식에서 아래 예의 x 와 같은 글로벌 변수에 접근해서 표현식을 평가하고 실행할 수 있습니다.  

 

## eval() has access to global names like x
x = 10
eval("x * 5")
# 50

 

 

 

eval() 함수는 문자열의 블리언 표현식 (Boolean expressions)에 대해서도 평가하여 실행할 수 있습니다.

 

아래의 예에서는 순서대로 블리언 표현식 (Boolean expressions)의 

  (a) 비교 연산자 (value comparison operstors: <, >, <=, >=, ==, !=)),

  (b) 논리 연산자 (logical operators: and, or, not),

  (c) 소속 여부 확인 연산자 (membership test operators: in, not in),

  (d) 동일 여부 확인 연산자 (identity operators: is, is not)

을 사용한 문자열 기반 인풋을 eval() 메소드를 통해 평가하고 실행해 보았습니다. 

 

## -- eval() for Boolean expressions
x = 10

## (a) value comparison operators: <, >, <=, >=, ==, !=
eval("x > 5")
# True


## (b) logical operstors: and, or, not
eval("x > 5 and x < 9")
# False


## (c) membership test operators: in, not in
eval("x in {1, 5, 10}")
# True


## (d) identity operators: is, is not
eval("x is 10")
# True

 

 

 

그러면, 그냥 Python 표현식을 쓰면 되지, 왜 굳이 문자열 기반의 표현식을 eval() 함수에 인풋으로 넣어서 쓸까 궁금할 것입니다. 아래의 조건 표현식을 가지는 사용자 정의 함수를 예로 들자면, 사용자 정의함수 myfunc() 를 사용할 때처럼 동적으로 문자열 기반의 조건절 표현식을 바꾸어가면서 쓸 수 있어서 강력하고 편리합니다. 

 

## suppose you need to implement a conditional statement, 
## but you want to change the condition on the fly, dynamically. 
def myfunc(a, b, condition):
    if eval(condition):
        return a + b
    return a - b
    
    
myfunc(5, 10, "a > b")
# -5


myfunc(5, 10, "a <= b")
# 15


myfunc(5, 10, "a is b")
# -5

 

 

 

(2) eval() 함수의 잘못된 사용 예시 (SyntaxError) 

 

(2-1) 만약 eval() 함수의 인풋으로 표현식(expressions) 이 아니라, if, while 또는 for 와 같은 키워드를 사용해서 만든 코드 블락으로 이루어진 명령문(statement)을 사용한다면 "SyntaxError: invalid syntax" 에러가 발생합니다. 

 

## if you pass a compound statement to eval(), 
## then you'll get a SyntaxError. 
x = 10
eval("if x>5: print(x)")
# File "<string>", line 1
#     if x>5: print(x)
#     ^
# SyntaxError: invalid syntax

 

 

 

(2-2) eval() 함수에 할당 연산(assignment operations: =) 을 사용하면 "SyntaxError: invalid syntax" 에러가 발생합니다. 

 

## Assignment operations aren't allowed with eval(). 
eval("x = 10")
# File "<string>", line 1
#     x = 10
#       ^
# SyntaxError: invalid syntax

 

 

 

(2-3) Python 구문의 규칙을 위배하면 "SyntaxError: unexpedted EOF while parsing" 에러가 발생합니다. 

(아래 예에서는 "1 + 2 -" 에서 문자열 마지막에 - 부호가 잘못 들어갔음) 

 

## If an expression violates Python syntax, then SyntaxError
eval("1 + 2 -")
# File "<string>", line 1
#     1 + 2 -
#           ^
# SyntaxError: unexpected EOF while parsing

 

 

 

(3) compiled-code-based 인풋을 eval() 함수에 사용하기

 

eval() 함수의 인풋으로 위의 문자열 기반 객체 대신 compiled-code-based 객체를 사용할 수도 있습니다. compiled-code-based 객체를 eval() 함수의 인풋으로 사용하면 아래의 두 단계를 거칩니다. 

 

  (3-a) 컴파일된 코드를 평가한다. (Evaluate the compiled code)

  (3-b) 평가 결과를 반환한다. (Return the result of the evaluation)

 

위의 (1)번에서 문자열 기반의 표현식을 eval() 함수의 인풋으로 사용했을 때 대비 compiled-code 객체를 eval() 함수의 인풋으로 사용할 경우 파싱하고 컴파일 하는 단계가 없고, 바로 컴파일된 코드를 평가하고 반환하는 단계로 넘어가므로 똑같은 표현식을 여러번 평가해야 하는 경우에 속도 향상을 기대할 수 있습니다. 

 

 

Python의 eval() 함수에 compiled code 객체를 인풋으로 사용하려면, 

compiled_code_object = compile(source, filename, mode) 의 구문을 사용해서 컴파일 해주면 됩니다. 

 - source 에는 문자열 표현식(string-based expression)을 넣어줍니다. 

 - filename 에는 문자열 기반 표현식을 사용할 경우 "<string>" 을 써줍니다. 

 - mode 에는 컴파일된 코드를 eval() 함수로 처리하길 원할 경우 "eval" 을 써줍니다. 

 

##-- eval() for compiled-code-based input
compiled_code = compile("(2 + 3) * 10", "<string>", "eval")
eval(compiled_code)
# 50

 

 

 

 

[ Reference ]

* Real Python site: "Python eval(): Evaluate Expressions Dynamically
: https://realpython.com/python-eval-function/

 

 

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

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

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 유닉스 스타일로 Python의 파일 경로와 파일명 패턴 매칭을 통해 찾아주는 glob, fnmatch 모듈에 대해서 알아보겠습니다. 

 

(1) glob: 유닉스 스타일 경로명 패턴 확장 (Unix style pathname pattern expansion)

(2) fnmatch: 유닉스 스타일 파일명 패턴 매칭 (Unix style filename pattern matching)

 

python glob, fnmatch module

 

 

(1) glob: 유닉스 스타일 경로명 패턴 확장 (Unix style pathname pattern expansion)

 

Python의 glob 모듈은 Unix shell에서 사용되는 규칙에 따라 지정된 패턴과 일치하는 모든 경로 이름을 찾아주며, 결과는 임의의 순서로 반환합니다. 

 

간단한 예를 들어서 설명해보겠습니다. 아래와 같은 파일경로의 계층으로 여러개의 파일이 있습니다. 

 

- data > glob 폴더내 'glob.ipynb' 파일, train 하위 폴더, test 하위 폴더

- data > glob > train 폴더 내 '1.txt', '2.txt', '1001.txt', '1002.txt', 'a.txt', 'b.txt', 'cat.jpeg'

- data > glob > test 폴더 내 '4.txt', '5.txt', 'd.txt', e.txt'

파일경로, 파일명 예시

 

 

(1-1) glob.glob('./*'): 현재 폴더의 폴더와 파일 경로 가져오기

 

import glob

## 현재 폴더의 폴더와 파일 경로
glob.glob('./*')

# ['./test', './glob.ipynb', './train']

 

 

(1-2) glob.glob(./foldername/*'): 특정 폴더 내 모든 파일 경로 가져오기

 

## ''./train' 경로의 모든 파일 경로
glob.glob('./train/*')

# ['./train/cat.jpeg',
#  './train/b.txt',
#  './train/a.txt',
#  './train/2.txt',
#  './train/1002.txt',
#  './train/1.txt',
#  './train/1001.txt']

 

 

(1-3) glob: 특정 폴더 내 특정 파일이름으로 끝나는 모든 파일 경로 가져오기 

 

예 1) '.txt' 로 끝나는 파일 경로

## '.txt' 로 끝나는 파일 경로
glob.glob('./train/*.txt')

# ['./train/b.txt',
#  './train/a.txt',
#  './train/2.txt',
#  './train/1002.txt',
#  './train/1.txt',
#  './train/1001.txt']

 

 

예 2) '.jpeg' 로 끝나는 파일 경로 

## '.jpeg' 로 끝나는 파일 경로
glob.glob('./train/*.jpeg')

# ['./train/cat.jpeg']

 

 

(1-4) glob.glob([0-9]*): 0~9 숫자로 시작하는 파일 경로 가져오기

 

## 0~9 숫자로 시작하는 파일 경로
glob.glob('./train/[0-9]*')

# ['./train/2.txt', 
#  './train/1002.txt', 
#  './train/1.txt', 
#  './train/1001.txt']

 

 

(1-5) glob.glob('./**/*', recursive=True)
  : 현재 폴더에 있는 폴더와 파일, 하위 폴더 내 모든 파일 경로 재귀적으로 가져오기

 

## ''**/*' 와 recursive=True : 현재 폴더에 있는 폴더와 파일, 하위 폴더 내 경로 재귀적으로 가져오기 
glob.glob('./**/*', recursive=True)

# ['./test',
#  './glob.ipynb',
#  './train',
#  './test/5.txt',
#  './test/4.txt',
#  './test/e.txt',
#  './test/d.txt',
#  './train/cat.jpeg',
#  './train/b.txt',
#  './train/a.txt',
#  './train/2.txt',
#  './train/1002.txt',
#  './train/1.txt',
#  './train/1001.txt']

 

 

(1-6) glob.glob('./**/*/', recursive=True): 현재 폴더에 있는 폴더 경로만 가져오기

 

## 제일 마지막에 '/' 추가: 폴더만
glob.glob('./**/*/', recursive=True)

# ['./test/', './train/']

 

 

(1-7) 디렉토리(<DIR>)와 파일(<FILE>) 구분자 추가해서 프린트 하기

 

import glob
from os.path import isdir

for x in glob.glob('./**/*', recursive=True):
    if isdir(x):
        print('<DIR> ', x) # 디렉토리
    else:
        print('<FILE>', x) # 파일
        
# <DIR>  ./test
# <FILE> ./glob.ipynb
# <DIR>  ./train
# <FILE> ./test/5.txt
# <FILE> ./test/4.txt
# <FILE> ./test/e.txt
# <FILE> ./test/d.txt
# <FILE> ./train/cat.jpeg
# <FILE> ./train/b.txt
# <FILE> ./train/a.txt
# <FILE> ./train/2.txt
# <FILE> ./train/1002.txt
# <FILE> ./train/1.txt
# <FILE> ./train/1001.txt

 

 

(1-8) 재귀하면서(recursive=True) 모든 폴더 내 파일 이름만 리스트로 가져오기

 

## 모든 폴더 내 파일 이름만 가져오기
import os

fnames = [
    os.path.basename(x) # 파일 이름
    for x in glob.glob('./**/*', recursive=True) # 재귀하면서 폴더&파일경로
    if not isdir(x) # 폴더 제외
]

print(fnames)

# ['glob.ipynb', 
#  '5.txt', 
#  '4.txt', 
#  'e.txt', 
#  'd.txt', 
#  'cat.jpeg', 
#  'b.txt', 
#  'a.txt', 
#  '2.txt', 
#  '1002.txt', 
#  '1.txt', 
#  '1001.txt']

 

 

(1-9) 재귀 대신 매뉴얼하게 모든 폴더를 지정해주어서 파일 이름만 리스트로 가져오기

 : 위의 (1-8) 재귀문과 결과 동일. 하위 폴더 개수가 많을 수록 (1-9) 수작업 코드 복잡해지고, 자동화에 제약 있음. 

 

## 파일 이름만 가져오기 : os.listdir() 이용해서
## 재귀 대신 매뉴얼하게 모든 폴더를 써줘야 함
import os

os.listdir('./') + os.listdir('./train/') + os.listdir('./test/')

# ['.DS_Store',
#  'test',
#  'glob.ipynb',
#  'train',
#  '.ipynb_checkpoints',
#  'cat.jpeg',
#  '.DS_Store',
#  'b.txt',
#  'a.txt',
#  '2.txt',
#  '1002.txt',
#  '1.txt',
#  '1001.txt',
#  '.DS_Store',
#  '5.txt',
#  '4.txt',
#  'e.txt',
#  'd.txt']

 

 

(1-10) 반복자(iterator) 반환하여 for loop 순환문에 사용하기

 

# glob.iglob(): 반복자(iterator) 반환
path_iterator = glob.iglob('./train/**.txt')

for path in path_iterator:
    print(path)
    
# ./train/b.txt
# ./train/a.txt
# ./train/2.txt
# ./train/1002.txt
# ./train/1.txt
# ./train/1001.txt

 

 

 

(2) fnmatch: 유닉스 스타일 파일명 패턴 매칭 (Unix style filename pattern matching)

 

fnmatch.fnmatch(filename, pattern) 메소드는 faiename 문자열이 pattern 문자열과 일치하는지를 검사하여, True나 False 를 반환합니다. 패턴 매칭하는 구문은 아래와 같습니다. 

 

    [seq] : seq 의 모든 문자와 일치합니다. 

    * : 모든 것과 일치합니다. 

 

 

(2-1) 특정 폴더 내 숫자로 시작('[0-9]*')하는 모든 파일 이름 가져오기

 

## filename 문자열이 pattern 문자열과 일치하는지를 검사하여, True 나 False를 반환합니다.
import fnmatch
import os

for file in os.listdir('./train'):
    # [seq]  seq의 모든 문자와 일치합니다.
    # *      모든 것과 일치합니다
    if fnmatch.fnmatch(file, '[0-9]*'):
        print(file)
        
# 2.txt
# 1002.txt
# 1.txt
# 1001.txt

 

 

(2-2) 특정 폴더 내 문자로 시작([!0-9]*')하는 모든 파일 이름 가져오기

 

for file in os.listdir('./train'):
    # [!seq] seq에 없는 모든 문자와 일치합니다
    if fnmatch.fnmatch(file, '[!0-9]*'):
        print(file)
        
# cat.jpeg
# b.txt
# a.txt

 

 

(2-3) 특정 폴더 내 특정 문자열로 끝나는 파일 이름 가져오기

 

for file in os.listdir('./train'):
    # *      모든 것과 일치합니다
    if fnmatch.fnmatch(file, '*.jpeg'):
        print(file)
        
# cat.jpeg

 

 

(2-4) 특정 폴더 내 모든 단일 문자('?')와 일치하는 파일 이름 가져오기

 

for file in os.listdir('./train'):
    # ?      모든 단일 문자와 일치합니다
    if fnmatch.fnmatch(file, '?.txt'):
        print(file)
        
# b.txt
# a.txt
# 2.txt
# 1.txt

 

 

(2-5) 특정 폴더 내 모든 파일 이름 가져오기

 

for file in os.listdir('./train'):
    # *      모든 것과 일치합니다
    if fnmatch.fnmatch(file, '*.txt'):
        print(file)
        
# b.txt
# a.txt
# 2.txt
# 1002.txt
# 1.txt
# 1001.txt

 

 

 

[Reference]

- glob module: https://docs.python.org/3/library/glob.html

- fnmatch module: https://docs.python.org/3/library/fnmatch.html#module-fnmatch

 

 

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

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

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 여러개의 Python 패키지, 모듈을 한꺼번에 설치하는 방법을 소개하겠습니다. 

 

(1) 설치하고자 하는 Python 패키지, 모듈 목록을 text 파일로 만들기

(2) 터미널에서 Python 패키지 목록 text 파일이 저장된 경로로 이동하기

(3) $ pip install -r requirements.txt 로 한꺼번에 Python 패키지 설치하기

(4) Python 패키지 설치 여부 확인하기

 

 

(1) 설치하고자 하는 Python 패키지, 모듈 목록을 text 파일로 만들기

 

예시로서 requirements.txt 파일에 아래의 화면 캡쳐한 것처럼 설치가 필요한 Python 패키지의 이름과 (필요 시) 버전을 적어서 정리하였습니다. 

 

Python package requirements

 

 

 

(2) 터미널에서 Python 패키지 목록 text 파일이 저장된 경로로 이동하기

 

터미널에서 shell script 를 사용해서 위의 (1)번에서 작성한 requirement.txt 파일이 저장되어 있는 파일 경로로 이동합니다. 

 

아래 예제에서는 /Users/lhongdon/Documents/my_project/requirements.txt 에 저장해두었으며,

$ cat requirements.txt 로 텍스트 파일에 정리해놓은 파이썬 모듈 리스트를 확인해볼 수 있습니다. 

 

-- current working directory
(base) lhongdon@lhongdon0MD6T ~ % pwd
/Users/lhongdon


-- display directories and files
(base) lhongdon@lhongdon0MD6T ~ % ls
??????			Hello-World		VirtualBox VMs		iCloud Drive (Archive)	postgres-data
??????.pub		Library			anaconda3		kubernetes		seaborn-data
Applications		Movies			df.csv			minikf			ssh-key-hdlee2u
Desktop			Music			examples		minikf-kubeconfig	ssh-key-hdlee2u.pub
Documents		Pictures		git-tutorial		nltk_data
Downloads		Public			github			opt
(base) lhongdon@lhongdon0MD6T ~ % 


-- move to the directory where requirements.txt file is saved
(base) lhongdon@lhongdon0MD6T ~ % cd Documents 
(base) lhongdon@lhongdon0MD6T Documents % ls
1_GPDB_DS_Training					my_project
2_KNOU								Modern-Computer-Vision-with-PyTorch-master
3_proposals							array_select
4_project							data
5_seminar							demo
7_personal							
8_Rfriend							
9_CV_PyTorch					

(base) lhongdon@lhongdon0MD6T Documents % cd my_project 
(base) lhongdon@lhongdon0MD6T my_project % 
(base) lhongdon@lhongdon0MD6T my_project % ls
requirements.txt
(base) lhongdon@lhongdon0MD6T my_project % 


-- display the contents in requirements.txt
(base) lhongdon@lhongdon0MD6T my_project % cat requirements.txt 
psycopg2
sqlalchemy==1.4.39
sql_magic
ipython-sql==0.3.9
pgspecial==1.11.5
pmdarima

(base) lhongdon@lhongdon0MD6T my_project %

 

 

 

(3) $ pip install -r requirements.txt 로 한꺼번에 Python 패키지 설치하기

 

터미널에서 requirements.txt 파일이 저장되어 있는 경로로 이동한 상태에서 

 

% pip install -r requirements.txt 

 

를 실행하면 requirements.txt 파일에 일목요연하게 정리되어있는 Python 모듈이 순차적으로 설치가 됩니다. 

 

-- installing multiple python modules
(base) lhongdon@lhongdon0MD6T my_project % pip install -r requirements.txt


Collecting psycopg2 (from -r requirements.txt (line 1))
  Downloading psycopg2-2.9.6.tar.gz (383 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 384.0/384.0 kB 667.4 kB/s eta 0:00:00
  Preparing metadata (setup.py) ... done
Requirement already satisfied: sqlalchemy==1.4.39 in /Users/lhongdon/anaconda3/lib/python3.10/site-packages (from -r requirements.txt (line 2)) (1.4.39)
Collecting sql_magic (from -r requirements.txt (line 3))
  Downloading sql_magic-0.0.4-py3-none-any.whl (10 kB)
Collecting ipython-sql==0.3.9 (from -r requirements.txt (line 4))
  Downloading ipython_sql-0.3.9-py2.py3-none-any.whl (21 kB)
Collecting pgspecial==1.11.5 (from -r requirements.txt (line 5))
  Downloading pgspecial-1.11.5.tar.gz (42 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 42.9/42.9 kB 1.3 MB/s eta 0:00:00
  Preparing metadata (setup.py) ... done
Collecting pmdarima (from -r requirements.txt (line 6))
  Downloading pmdarima-2.0.3-cp310-cp310-macosx_10_9_x86_64.whl (607 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 607.3/607.3 kB 2.7 MB/s eta 0:00:00
Requirement already satisfied: greenlet!=0.4.17 in /Users/lhongdon/anaconda3/lib/python3.10/site-packages (from sqlalchemy==1.4.39->-r requirements.txt (line 2)) (2.0.1)
Collecting prettytable (from ipython-sql==0.3.9->-r requirements.txt (line 4))
  Downloading prettytable-3.8.0-py3-none-any.whl (27 kB)
Requirement already satisfied: ipython>=1.0 in /Users/lhongdon/anaconda3/lib/python3.10/site-packages (from ipython-sql==0.3.9->-r requirements.txt (line 4)) (8.10.0)
Collecting sqlparse (from ipython-sql==0.3.9->-r requirements.txt (line 4))
  Downloading sqlparse-0.4.4-py3-none-any.whl (41 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 41.2/41.2 kB 1.3 MB/s eta 0:00:00
Requirement already satisfied: six in /Users/lhongdon/anaconda3/lib/python3.10/site-packages (from ipython-sql==0.3.9->-r requirements.txt (line 4)) (1.16.0)
-- 이하 생략

 

 

 

(4) Python 패키지 설치 여부 확인하기

 

터미널에서 

% pip show [Python Module Name] 

 

을 실행하면 해당 Python 모듈의 설치 여부 및 상세 내역을 확인할 수 있습니다. 

 

-- check the details of python module installed
(base) lhongdon@lhongdon0MD6T my_project % pip show sql_magic

Name: sql-magic
Version: 0.0.4
Summary: UNKNOWN
Home-page: UNKNOWN
Author: Chris Rawles
Author-email: crawles@gmail.com
License: UNKNOWN
Location: /Users/lhongdon/anaconda3/lib/python3.10/site-packages
Requires: findspark, ipython, jupyter, pandas, sqlparse, traitlets
Required-by: 
(base) lhongdon@lhongdon0MD6T my_project % 
(base) lhongdon@lhongdon0MD6T my_project %

 

 

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

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

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Jupyter Notebook 의 기본 사용법 중에서 

 

(1) Jupyter Notebook Cell 의 모든 결과 지우기 

    : Cell >> All Output >> Clear

(2) Jupyter Notebook 커널 새로 시작하고, 모든 Cell 실행하기

    : Kernel >> Restart & Run All

 

방법에 대해서 소개하겠습니다. 

 

 

(1) Jupyter Notebook Cell 의 모든 결과 지우기

    : Cell >> All Output >> Clear

 

 

아래에 예제로 사용할 간단한 Jupyter Notebook 을 만들어보았습니다.

x, y 객체를 프린트도 해보고, 선 그래프도 그려보았습니다.  

Jupyter Notebook Cell's Results

 

 

이제 Cell >> All Output >> Clear 순서로 메뉴를 선택해서 Cell의 모든 결과를 지워보겠습니다. 

(Clear the output of all cells in Jupyter Notebook) 

 

Jupyter Notebook - Cell - All Output - Clear

 

 

Cell >> All Output >> Clear 의 순서대로 메뉴를 선택해서 실행하면 아래처럼 Cell 의 결과가 모두 지워져서 깨끗해졌습니다. 

Jupyter Notebook - Cleared All Outputs in Cells

 

 

 

(2) Jupyter Notebook 커널 새로 시작하고, 모든 Cell 실행하기

    : Kernel >> Restart & Run All

 

위의 (1)번과는 반대로, 이번에는 Kernel 을 새로 시작(Kernel Restart)하고 모든 Cell을 새로 실행(Run All)해보겠습니다. 

(Kernel >> Restart & Run All)

Jupyter Notebook - Restart & Run All

 

 

아래와 같은 팝업 창이 뜨면 "Restart and Run All Cells" 메뉴를 선택해서 클릭해주면 됩니다. 

 

Jupyter Notebook - Restart and Run All Cells

 

 

그러면, 아래처럼 커널이 새로 시작하고, 모든 셀이 순서대로 다시 실행이 됩니다. 

Jupyter Notebook - Restart and Run All Cells - Results

 

 

 

 

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

행복한 데이터 과학자 되세요. 

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python을 사용해서 웹사이트에서 압축파일을 다운로드해서 압축을 해제하고 데이터셋을 합치는 방법을 소개하겠습니다. 

 

세부 절차 및 이용한 Python 모듈과 메소드는 아래와 같습니다. 

 

(1) os 모듈로 다운로드한 파일을 저장할 디렉토리가 없을 경우 새로운 디렉토리 생성하기

(2) urllib.request.urlopen() 메소드로 웹사이트를 열기 

(3) tarfile.open().extractall() 메소드로 압축 파일을 열고, 모든 멤버들을 압축해제하기

(4) pandas.read_csv() 메소드로 파일을 읽어서 DataFrame으로 만들기

(5) pandas.concat() 메소드로 모든 DataFrame을 하나의 DataFrame으로 합치기

(6) pandas.to_csv() 메소드로 합쳐진 csv 파일을 내보내기

 

 

먼저, 위의 6개 절차를 download_and_merge_csv() 라는 이름의 사용자 정의함수로 정의해보겠습니다.  

 

import os
import glob
import pandas as pd
import tarfile
import urllib.request

## downloads a zipped tar file (.tar.gz) that contains several CSV files, 
## from a public website. 
def download_and_merge_csv(url: str, down_dir: str, output_csv: str):
    """
    - url: url address from which you want to download a compressed file
    - down_dir: directory to which you want to download a compressed file
    - output_csv: a file name of a exported DataFrame using pd.to_csv() method
    """
    
    # if down_dir does not exists, then create a new directory
    down_dir = 'downloaded_data'
    if os.path.isdir(down_dir):
        pass
    else:
        os.mkdir(down_dir)
        
    # Open for reading with gzip compression.
    # Extract all members from the archive to the current working directory or directory path. 
    with urllib.request.urlopen(url) as res:
        tarfile.open(fileobj=res, mode="r|gz").extractall(down_dir)
    
    # concatenate all extracted csv files
    df = pd.concat(
        [pd.read_csv(csv_file, header=None) 
         for csv_file in glob.glob(os.path.join(down_dir, '*.csv'))])
    
    # export a DataFrame to a csv file
    df.to_csv(output_csv, index=False, header=False)

 

참고로, tarfile.open(fileobj, mode="r") 에서 4개의 mode 를 지원합니다. 

tarfile(mode) 옵션
-. mode="r": 존재하는 데이터 보관소로부터 읽기 (read)
-. mode="a": 존재하는 파일에 데이터를 덧붙이기 (append)
-. mode="w": 존재하는 파일을 덮어쓰기해서 새로운 파일 만들기 (write, create a new file overwriting an existing one)
-. mode="x": 기존 파일이 존재하지 않을 경우에만 새로운 파일을 만들기 (create a new file only if it does not already exist)

* for more information on tarfile module: https://docs.python.org/3/library/tarfile.html

 

 

현재 Jupyter Notebook 커널의 디렉토리에는 아래처럼  아직 다운로드한 파일이 없습니다. 

 

jovyan@kubecon-tutorial-0:~$ pwd
/home/jovyan
jovyan@kubecon-tutorial-0:~$ 
jovyan@kubecon-tutorial-0:~$ ls
data  down_merge_csv.ipynb  kale.log  lost+found
jovyan@kubecon-tutorial-0:~$ 
jovyan@kubecon-tutorial-0:~$

 

 

 

 

이제 위에서 정의한 download_and_merge_csv() 를 사용해서 

  (a) url='https://storage.googleapis.com/ml-pipeline-playground/iris-csv-files.tar.gz' 로 웹사이트로 부터 압축파일을 열고 모든 파일들을 해제해서 

  (b) down_dir='downloaded_data' 의 디렉토리에 다운로드하고, 

  (c) output_csv='iris_merged_data.csv'  라는 이름의 csv 파일로 모든 파일을 합쳐서 내보내기

를 해보겠습니다. 

 

download_and_merge_csv(
    url='https://storage.googleapis.com/ml-pipeline-playground/iris-csv-files.tar.gz', 
    down_dir='downloaded_data', 
    output_csv='iris_merged_data.csv')

 

 

아래의 화면캡쳐처럼 'iris_merged_data.csv' 라는 이름의 csv 파일이 새로 생겼습니다. 그리고 'downloaded_data' 라는 폴더도 새로 생겼습니다. 

 

 

 

 

터미널에서 새로 생긴 'downloaded_data' 로 디렉토리를 이동한 다음에, 파일 리스트를 확인해보니 'iris-1.csv', 'iris-2.csv', 'iris-3.csv' 의 3개 파일이 들어있네요. head 로 상위의 10 개 행을 읽어보니 iris 데이터셋이군요. 

 

jovyan@kubecon-tutorial-0:~$ ls
data  downloaded_data  down_merge_csv.ipynb  iris_merged_data.csv  kale.log  lost+found
jovyan@kubecon-tutorial-0:~$ 
jovyan@kubecon-tutorial-0:~$ 
jovyan@kubecon-tutorial-0:~$ cd downloaded_data/
jovyan@kubecon-tutorial-0:~/downloaded_data$ ls
iris-1.csv  iris-2.csv  iris-3.csv
jovyan@kubecon-tutorial-0:~/downloaded_data$ 
jovyan@kubecon-tutorial-0:~/downloaded_data$ 
jovyan@kubecon-tutorial-0:~/downloaded_data$ head iris-1.csv
5.1,3.5,1.4,0.2,setosa
4.9,3.0,1.4,0.2,setosa
4.7,3.2,1.3,0.2,setosa
4.6,3.1,1.5,0.2,setosa
5.0,3.6,1.4,0.2,setosa
5.4,3.9,1.7,0.4,setosa
4.6,3.4,1.4,0.3,setosa
5.0,3.4,1.5,0.2,setosa
4.4,2.9,1.4,0.2,setosa
4.9,3.1,1.5,0.1,setosa
jovyan@kubecon-tutorial-0:~/downloaded_data$

 

 

 

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

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

 

728x90
반응형
Posted by Rfriend
,

ZIP 파일 포맷은 일반적으로 자료를 압축하여 보관하는 표준 포맷입니다. 대용량의 데이터를 압축하는 것은 데이터 저장 공간을 적게 사용하고, 데이터 전송에 있어서도 성능 향상을 기대할 수 있으며, 하나의 압축된 파일로 관리할 수 있어 편리합니다.


Python의 zipfile 모듈은 ZIP 파일을 생성하고, 읽기, 쓰기, 추가하기, 압축 파일 해제하기, 압축 파일 리스트와 정보 보기 등을 할 수 있는 클래스를 제공합니다.


이번 포스팅에서는 Python의 zipfile 모듈을 사용해서 (Python 3.x 버전 기준)


(1) 압축 ZIP 파일 쓰기 (write)

(2) 압축 ZIP 파일 읽기 (read)

(3) 압축 ZIP 파일 이름(filename), 자료 리스트(namelist()), 파일 정보(getinfo) 보기

(4) 압축 ZIP 파일 해제하기 (extract)

(5) 웹에서 압축 ZIP 파일 다운로드하여 압축 해제하기 (download and extract)



[ Python zipfile 모듈로 압축 파일 쓰기, 읽기, 해제하기 ]



  (1) 압축 ZIP 파일 쓰기 (write)


먼저, Python으로 (a) 압축 ZIP 파일을 다루는 zipfile 모듈과, (b) 경로(directory, path) 및 폴더/파일을 관리를 할 수 있게 해주는 os 모듈을 importing 하겠습니다.

(cf. Python의 os 모듈을 사용해서 경로 및 폴더/파일 관리하는 방법은 https://rfriend.tistory.com/429 포스팅을 참고하세요.)


다음으로, os 모듈의 chdir() 함수를 사용해서 "Downloads" 폴더로 작업 경로를 변경하겠습니다.

os.getcwd() 로 현재 작업 경로를 확인해보니 "Downloads" 폴더로 작업 경로가 잘 변경되었네요.

os.listdir() 은 현재 작업 경로에 들어있는 파일 리스트를 반환합니다. ['sample_1.txt', 'sample_2.txt', 'sample_3.txt'] 의 3개 텍스트 파일이 예제로 들어있습니다.



import zipfile
import os


## change working directory
base_dir = '/Users/ihongdon/Downloads'
os.chdir(base_dir)

## check the current working directory
os.getcwd()

[Out] '/Users/ihongdon/Downloads'


## show the lists of files in the current working directory
os.listdir()

['sample_2.txt', 'sample_3.txt', 'sample_1.txt']




(1-1) mode='w' : 새로운 압축 파일 쓰기 (단, 기존 압축 파일 있으면 덮어쓰기)


zipfile.ZipFile(file, mode='r') 에서 mode 에는 'w', 'x', 'a', 'r'의 4개 모드가 있고, 기본 설정값은 'r' (읽기) 입니다. 이들 4개 모드별 기능은 아래와 같습니다.


[ zipfile.ZipFile(file, mode) 에서 mode='w'/'x'/'a'/'r' 별 기능 ]

  • mode='w': 새로운 ZIP 압축 파일을 쓰기 (단, 기존 압축 파일이 있으면 덮어쓰기)
                   (to truncate and write a new file)
  • mode='x': 새로운 ZIP 압축 파일을 쓰기 (단, 기존 압축 파일이 있으면 FileExistsError 발생)
                   (to exclusively create and write a new file)
  • mode='a': 기존 ZIP 압축 파일에 자료 추가하기 (to append additional files to an existing ZIP file)
  • mode='r': 기존 ZIP 압축 파일의 자료 읽기 (to read an existing file). 기본 설정 값


myzip_w = zipfile.ZipFile('sample.zip', 'w') 로 'myzip_w'라는 이름의 ZipFile 객체를 새로 만들어 주고, myzip_w.write('sample_1.txt') 함수로 'sample.zip'의 ZIP 파일에 'sample_1.txt' 텍스트 파일을 압축해서 써줍니다.


ZIP 파일을 열고나서 작업 (쓰기, 추가하기, 읽기 등)이 다 끝났으면 시스템이나 프로그램을 종료하기 전에 ZipFile.close() 메소드를 써서 작업 중인 ZIP 파일을 닫아주어야 합니다. 만약 close() 를 하지 않은 상태에서 프로그램을 종료하면 ZIP 파일에 정상적으로 자료가 기록이 되지 않을 것입니다.


ZipFile.is_zipfile(file) 메소드는 ZIP 파일이 존재하면 TRUE를 반환하고, 존재하지 않으면 FALSE를 반환합니다.



## (1) mode='w': to truncate and write a new file
myzip_w = zipfile.ZipFile('sample.zip', 'w')
myzip_w.write('sample_1.txt')

## You must call close() before exiting your program,
## or essential records will not be written.
myzip_w.close()


## ZipFile.is_zipfile(): Return True if a valid ZIP file exists.
zipfile.is_zipfile('sample.zip')

[Out] True




ZipFile 객체는 맥락 관리자(context manager) 이므로 'with 문 (with statement)' 을 지원합니다. 따라서 위의 (1-1) 예제 코드를 아래처럼 with 문을 사용해서 ZIP 파일 쓰기를 할 수도 있습니다.



with zipfile.ZipFile('sample.zip', 'w') as myzip:
    myzip.write('sample_1.txt')
    myzip.close()

 




(1-2) mode='x' : 새로운 압축 파일 쓰기 (단, 기존 파일 있으면 FileExistsError 발생)


위의 mode='w'와는 달리, mode='x'는 새로운 압축 파일을 생성할 때 만약 같은 이름의 ZIP 파일이 존재한다면 'FileExistsError' 가 발생한다는 점이 다릅니다. (to exclusively create and write a new file.)


위의 (1-1)번 예에서 'sample.zip' 이름의 ZIP 파일을 이미 만들었습니다. 여기에 zipfile.ZipFile('sample.zip', mode='x') 로 해서 'sample.zip' 파일 이름으로 ZIP 압축 파일을 만들려고 하면 아래처럼 'FileExistsError: [Errno 17] File exists: 'sample.zip' 의 에러가 발생합니다.



## (2) mode='x': to exclusively create and write a new file.
## if file refers to an existing file, a 'FileExistsError' will be raised.
myzip_x = zipfile.ZipFile('sample.zip', 'x')

[Out]
--------------------------------------------------------------------------- FileExistsError Traceback (most recent call last) <ipython-input-7-bd84b411165c> in <module> 1 ## (2) mode='x': to exclusively create and write a new file. 2 ## if file refers to an existing file, a 'FileExistsError' will be raised. ----> 3 myzip_x = zipfile.ZipFile('sample.zip', 'x') ~/opt/anaconda3/lib/python3.8/zipfile.py in __init__(self, file, mode, compression, allowZip64, compresslevel, strict_timestamps) 1249 while True: 1250 try: -> 1251 self.fp = io.open(file, filemode) 1252 except OSError: 1253 if filemode in modeDict: FileExistsError: [Errno 17] File exists: 'sample.zip'

 



위의 'FileExistsError'가 발생했다면, 아래처럼 ZIP 파일 이름을 기존에는 없는 파일 이름으로 바꾸어서 zipfile.ZipFile(new_file_name, mode='x') 로 해서 압축 파일을 생성할 수 있습니다.

(mode='w' 로 하면 기존 파일을 덮어쓰기 하므로 주의가 필요합니다.)


ZipFile.namelist() 는 ZipFile 객체에 압축되어 있는 자료(archives)의 이름 리스트를 출력해줍니다.



myzip_x = zipfile.ZipFile('sample2.zip', 'x')
myzip_x.write('sample_2.txt')
myzip_x.close()

myzip_x.namelist()

[Out] ['sample_2.txt']





(1-3) mode='a' : 기존 ZIP 압축 파일에 자료 추가 (to append, add up)


만약 기존에 존재하는 ZIP 파일에 새로운 자료를 추가(append)하고 싶다면 mode='a' 로 설정해주면 됩니다.


아래 예제에서는 위의 (1-1)에서 'sample_1.txt'의 텍스트 파일을 'sample.zip' 이름으로 압축해서 이미 만들어두었던 ZIP 파일에 더하여, 'sample_2.txt', 'sample_3.txt' 의 텍스트 파일까지 추가하여 'sample.zip' 이름의 ZIP 파일에 압축해보겠습니다.



## (3) mode='a': to append to an existing file.
myzip_a = zipfile.ZipFile('sample.zip', 'a')
myzip_a.write('sample_2.txt')
myzip_a.write('sample_3.txt')
myzip_a.close()

myzip_a.namelist()

[Out] ['sample_1.txt', 'sample_2.txt', 'sample_3.txt']





(1-4) 여러개의 자료를 하나의 압축 ZIP 파일에 쓰기 (for loop, ZipFile(), write())


하나의 ZIP 압축 파일에 여러개의 자료를 압축해서 쓰고 싶을 때는 for loop 반복문을 같이 사용해주면 됩니다. (mode 는 필요와 상황에 맞게 'w', 'x', 'a' 중에서 선택)


아래 예제는 'myzip_all' 이름의 ZipFile 객체로 'sample_all.zip' 의 ZIP 파일에 ['sample_1.txt', 'sample_2.txt', 'sample_3.txt'] 의 3개 텍스트 파일들을 for loop 반복문을 사용해서 하나씩 차례대로 호출해서 myzip_all.write(f) 로 'sample_all.zip' 파일에 써주었습니다.



## (4) writing files to a zip file: with statement & for loop
file_list = ['sample_1.txt', 'sample_2.txt', 'sample_3.txt']

with zipfile.ZipFile('sample_all.zip', 'w') as myzip_all:
    for f in file_list:
        myzip_all.write(f)
        print(f, 'is written to myzip_all.zip')
    myzip_all.close()


[Out]
sample_1.txt is written to myzip_all.zip sample_2.txt is written to myzip_all.zip sample_3.txt is written to myzip_all.zip


myzip_all.namelist()

[Out] ['sample_1.txt', 'sample_2.txt', 'sample_3.txt']





(1-5) zipfile.ZipFile(file, mode='r',

           compression=ZIP_STORED, allowZip64=True, compresslevel=None)


매개변수

설명

 compression

 compression은 자료를 압축 파일에 쓰기 위한 ZIP 압축 메소드이며, 기본 설정값은 ZIP_STORED 입니다.


Python 버전 3.1 부터 아래의 파일과 같은 객체를 지원합니다.

  • zipfile.ZIP_STORED  (* default)
  • zipfile.ZIP_DEFLATED
  • zipfile.ZIP_BZIP2

Python 버전 3.3 부터는 ZIP_LZMA 객체를 지원합니다.

  • zipfile.ZIP_LZMA

 allowZip64

 allowZip64=True (기본 설정) 이면 ZIP 파일 크기가 4GB를 넘을 경우 ZIP64 extensions 를 사용해서 ZIP 파일을 생성합니다.

 

 만약 allowZip64=False 설정인데 ZIP 파일 크기가 4GB를 넘을 경우에는 exception error 가 발생합니다.

 compresslevel

 compresslevel 매개변수는 자료를 압축할 수준을 지정할 때 사용합니다.

(compression 이 ZIP_STORED, ZIP_LZMA 일 경우에는 효과가 없으며, ZIP_DEPLATED, ZIP_BZIP2 에만 설정 가능합니다.)

  • compression=ZIP_DEFLATED 일 경우 compresslevel=0~9 까지 설정 가능
  • compression=ZIP_BZIP2 일 경우 compresslevel=1~9 까지 설정 가능




  (2) 압축 ZIP 파일 읽기 (read)


ZIP 압축 파일에 들어있는 자료를 읽으려면 zipfile.ZipFile(file, mode='r') 로 해서 ZipFile 객체를 '읽기 모드'로 생성한 후, ZipFile.read() 메소드로 ZIP 파일 내 압축되어 있는 자료를 읽을 수 있습니다.

아래 예제는 위의 (1-1)에서 만들었던 'sample.zip'의 ZIP 파일 안에 압축되어 있는 'sample_1.txt' 텍스트 자료를 읽어본 것입니다. 압축을 해제하지 않고도 ZIP 압축 파일 내의 특정 자료를 선택해서 그 자료만 읽을 수 있어서 편리합니다.


## sample.zip
myzip_w.namelist()

[Out] ['sample_1.txt']


## mode='r': to read an existing file
myzip_r = zipfile.ZipFile('sample.zip', 'r')
print(myzip_r.read('sample_1.txt'))

[Out] b'x1,x2,x3\n1,2,3\n4,5,6\n7,8,9\n'


# ## or equivalently above
# with myzip_r.open('sample_1.txt') as s1:
#     print(s1.read())




위의 압축 파일 내 자료를 읽은 결과가 눈에 잘 안들어 올 수도 있는데요, 아래에는 참고로 pandas 의 read_csv() 메소드를 사용해서 'sample_1.txt' 파일을 출력해본 것입니다.


import pandas as pd

sample_1_df = pd.read_csv('sample_1.txt')
print(sample_1_df)

[Out]
x1 x2 x3 0 1 2 3 1 4 5 6 2 7 8 9





  (3) 압축 ZIP 파일 이름(filename), 자료 리스트(namelist()), 파일 정보(getinfo) 보기


(3-1) ZipFile.is_zipfile(file) : Zip 파일이 존재하면 True, 존재하지 않으면 False



file_list = ['sample_1.txt', 'sample_2.txt', 'sample_3.txt']

with zipfile.ZipFile('sample_all.zip', 'w') as myzip_all:
    for f in file_list:
        myzip_all.write(f)
    myzip_all.close()


## ZipFile.is_zipfile(): Return True if a valid ZIP file exists.
zipfile.is_zipfile('sample_all.zip')

[Out] True

 



(3-2) ZipFile.filename : ZIP 압축 파일 이름 출력



## ZipFile.filename: Name of the ZIP file
myzip_all.filename

[Out] 'sample_all.zip'




(3-3) ZipFile.namelist() : ZIP 압축 파일 내 자료 이름 리스트 출력



## file name lists of sample_all.zip
myzip_all.namelist()

[Out] ['sample_1.txt', 'sample_2.txt', 'sample_3.txt']




(3-4) ZipFile.getinfo(member) : ZIP 파일 내 자료(member)의 정보 출력


파일 이름 (file name), 파일 모드 (file mode), 파일 크기 (file size)



## ZipFile.getinfo(): Zip information about the archive member name.
myzip_all.getinfo('sample_1.txt')

[Out] <ZipInfo filename='sample_1.txt' filemode='-rw-r--r--' file_size=27>




  (4) 압축 ZIP 파일 해제하기 (extract)


(4-1) ZipFile.extract(file, path) : ZIP 파일 내 1개의 자료만 압축 해제하기


이때 압축을 해제한 자료를 저장할 경로(path)를 별도로 지정해 줄 수 있습니다. (path 를 지정하지 않으면 현재 작업경로에 압축 해제함)



## (4-1) ZipFile.extract()
## : extracting a member from the archive to the current working directory.
extract_path = '/Users/ihongdon/Downloads/sample_3'
zipfile.ZipFile('sample_all.zip').extract('sample_3.txt', path=extract_path)

[Out] '/Users/ihongdon/Downloads/sample_3/sample_3.txt'

 



위의 (4-1)에서는 압축 해제한 1개 파일을 저장할 경로(path)를 지정해주었는데요, 해당 경로에 os.listdir(extract_path) 로 확인해 보니 원하는 'sample_3.txt' 텍스트 자료가 잘 압축 해제되어 저장되어 있네요.



os.listdir(extract_path)

[Out] ['sample_3.txt']

 



(4-2) ZipFile.extractall() : ZIP 파일 내 모든 자료를 압축 해제



## (4-2) ZipFile.extractall()
## : extracting all members from the archive to the current working directory.
extractall_path = '/Users/ihongdon/Downloads/sample_all'
zipfile.ZipFile('sample_all.zip').extractall(extractall_path)


os.listdir(extractall_path)

[Out] ['sample_2.txt', 'sample_3.txt', 'sample_1.txt']





  (5) 웹에서 ZIP 파일 다운로드하여 압축 해제하기 (download and extract ZIP file)


아래 예제는 웹사이트에서 영화 추천에 사용되는 영화 평가 점수(movie ratings)를 모아놓은  데이터셋('movielens.csv', etc.)ZIP 포맷으로 압축해 놓은 'ml-latest-small.zip' 파일을 Keras의 메소드를 사용해 다운로드 한 다음에, zipfile 모듈의 ZipFile.extractall() 메소드로 전체 자료를 압축 해제한 것입니다.



## Download the movielens data from website url
import tensorflow.keras as keras
from zipfile import ZipFile
from pathlib import Path

import os


movielens_data_file_url = (
    "http://files.grouplens.org/datasets/movielens/ml-latest-small.zip"
)

movielens_zipped_file = keras.utils.get_file(
    "ml-latest-small.zip", movielens_data_file_url, extract=False
)

keras_datasets_path = Path(movielens_zipped_file).parents[0]
movielens_dir = keras_datasets_path / "ml-latest-small"

## Only extract the data the first time the script is run.
if not movielens_dir.exists():
    with ZipFile(movielens_zipped_file, "r") as zip:
        zip.extractall(path=keras_datasets_path) # extract all members in a ZIP file

 



사용자 별 영화 평가점수('ratings.csv')와 영화 정보('movies.csv') 데이터셋을 사용해서 영화 추천 (movie recommentation) 에 사용할 수 있습니다.



print('datasets path:', keras_datasets_path)

[Out] datasets path: /Users/ihongdon/.keras/datasets


print(os.listdir(keras_datasets_path))

[Out] ['cowper.txt', 'reuters_word_index.json', 'imdb_word_index.json', 'flower_photos.tar.gz', 'cifar-10-batches-py', 'mnist.npz', 'ml-latest-small.zip', 'ml-latest-small', 'fashion-mnist', 'butler.txt', 'imdb.npz', 'cifar-10-batches-py.tar.gz', 'boston_housing.npz', 'creditcard.csv', 'creditcard.zip', 'derby.txt', 'train.csv', 'flower_photos', 'reuters.npz', 'fsns.tfrec']

os.listdir(movielens_dir)

[Out] ['links.csv', 'tags.csv', 'ratings.csv', 'README.txt', 'movies.csv']



[Reference]

* zipfile -Work with ZIP archives: https://docs.python.org/3/library/zipfile.html


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

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



728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 (1) 파이썬의 자료형 중에서도 사전형(Dictionary)을 키와 값 (Key and Value) 의 쌍으로 인쇄를 할 때 좀더 가독성을 좋게 하도록 키(Key) 에서 일정 간격을 띄우고 나서 값(Value)을 인쇄하는 옵션을 소개하겠습니다.  


그리고 소소한 팁으로 (2) 파이썬 인쇄 escape 옵션, (3) 파이썬 인쇄 sep, end 옵션을 추가로 소개하겠습니다. 



  (1) 파이썬 사전형의 키와 값을 일정 간격을 두고 인쇄하기

      (Print Key, Value of Python Dictionary with fixed space)




먼저, 예제로 사용할 간단한 파이썬 사전형(Dictionary) 객체를 키와 값의 쌍(pair of key and value)으로 만들어보고 print() 로 인쇄를 해보겠습니다


사전형 객체에 대해서 그냥 print() 로 인쇄를 하면 옆으로 길게 쭈욱~ 늘어서 인쇄가 되기 때문에 아무래도 한눈에 보기가 쉽지 않습니다. 



my_dict = {'first name': 'KilDong.', 

           'last name': 'Hong.',

           'age': '30.', 

           'address': 'Seoul, Korea.'}



print(my_dict)

[Out]

{'first name': 'KilDong.', 'last name': 'Hong.', 'age': '30.', 'address': 'Seoul, Korea.'}





그러면, 좀더 보기에 좋도록 이번에는 dictionary.items() 로 키와 값을 분해해서 각각 가져오고, for loop 순환문으로 반복을 하면서 각 키와 값을 한줄에 하나씩 인쇄를 해보겠습니다. 이때 format() 메소드를 사용해서 Key, Value 값을 인쇄할 때 각각 치환해주었습니다. 

바로 앞의 예에서 그냥 print() 한 것보다는 한결 보기에 좋습니다만, Key 문자열의 길이가 들쭉날쭉 하다보니 Key : Value 로 쌍을 이루어서 인쇄를 할 때 Value 인쇄가 시작하는 위치도 역시 들쭉날쭉해서 좀 정신이 없고 눈에 잘 안들어오는 한계가 있습니다. 



for k, v in my_dict.items():

    print("{} : {}".format(k, v))


[Out]
first name : KilDong.
last name : Hong.
age : 30.
address : Seoul, Korea.





이럴 때 {!r:15s} 으로 특정 숫자만큼의 string 간격을 두고 인쇄하라는 옵션을 추가해주면 아래와 같이 Key 문자열의 시작위치부터 15 string 만큼 각격을 두고, 이어서 다음의 문자열(여기서는 ': {value}')을 인쇄하게 됩니다. 위의 예보다는 아래의 예가 한결 Key : Value 쌍을 한눈에 보기에 좋아졌습니다.   



for k, v in my_dict.items():

    print("{!r:15s} : {}".format(k, v))


[Out]

'first name' : KilDong. 'last name' : Hong. 'age' : 30. 'address' : Seoul, Korea.

 





  (2) 파이썬 인쇄 escape 옵션 (Python Print escape options)

파이썬 문법을 탈출(escape)하여 인쇄할 수 있는 소소한 옵션들이 몇 개 있습니다. 

(아래에서 \ 는 역슬래쉬  , back-slash 입니다)


  • \n : 새로운 줄로 바꾸어서 인쇄하기
  • \t : 탭(tab)으로 들여쓰기해서 인쇄하기 (오른쪽으로 탭한 만큼 밀어서 인쇄)
  • \b : 뒤에서 한칸 back-space 하여 인쇄하기 (제일 뒤에 문자가 있으면 삭제되어서 인쇄)
  • \" : 큰 따옴표(") 인쇄하기
  • \' : 작은 따옴표(') 인쇄하기
  • \\ : 역슬래쉬('\') 인쇄하기


  • \n : 새로운 줄로 바꾸어서 인쇄하기


for k, v in my_dict.items():

    print("\n{} : {}".format(k, v))


[Out]

first name : KilDong.

last name : Hong.

age : 30.

address : Seoul, Korea.





  • \t : 탭(tab)으로 들여쓰기해서 인쇄하기 (오른쪽으로 탭한 만큼 밀어서 인쇄)


for k, v in my_dict.items():

    print("\t{} : {}".format(k, v))


[Out]
	first name : KilDong.
	last name : Hong.
	age : 30.
	address : Seoul, Korea.





  • \b : 뒤에서 한칸 back-space 하여 인쇄하기 (제일 뒤에 문자가 있으면 삭제되어서 인쇄)



for k, v in my_dict.items():

    print("{} : {}\b".format(k, v))


[Out]
first name : KilDong
last name : Hong
age : 30
address : Seoul, Korea

 




  • \" : 큰 따옴표(") 인쇄하기


for k, v in my_dict.items():

    print("{} : \"{}\"".format(k, v))


[Out]
first name : "KilDong."
last name : "Hong."
age : "30."
address : "Seoul, Korea."

 




  • \\ : 역슬래쉬('\') 인쇄하기


for k, v in my_dict.items():

    print("{} : \\{}\\".format(k, v))


[Out]
first name : \KilDong.\
last name : \Hong.\
age : \30.\
address : \Seoul, Korea.\

 





  (3) 파이썬 인쇄 sep, end 옵션 (Python Print sep, end options)


  • sep="separator" 옵션 : 두 개의 문자열 사이에 구분자(separator) 문자로 구분하여 붙여서 인쇄
  • end="end_string" 옵션 : 앞의 문자열에 바로 이어서 end_string을 붙여서 인쇄


앞의 (1)번에서 예로 들었던 Key : Value 쌍으로 item 한줄씩 인쇄하는 것을 sep, end 옵션을 사용해서 똑같이 재현해보겠습니다. 


  • sep="separator" 옵션 : 두 개의 문자열 사이에 구분자(separator) 문자로 구분하여 붙여서 인쇄


for k, v in my_dict.items():

    print(k, v, sep=" : ")


[Out]

first name : KilDong. last name : Hong. age : 30. address : Seoul, Korea.

 




  • end="end_string" 옵션 : 앞의 문자열에 바로 이어서 end_string을 붙여서 인쇄


for k, v in my_dict.items():

    print(k + " : ", end=v+"\n")


[Out]
first name : KilDong.
last name : Hong.
age : 30. 

address : Seoul, Korea.




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

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



728x90
반응형
Posted by Rfriend
,

Python은 고수준의 객체지향 프로그래밍 언어입니다. 파이썬 툴을 사용해 재사용 가능한 코드를 작성하는 기능은 파이썬이 가지고 있는 큰 장점 중의 하나입니다. 


Python Functools 는 고차함수(high order functions)를 위해 설계된 라이브러리로서, 호출 가능한 기존의 객체, 함수를 사용하여 다른 함수를 반환하거나 활용할 수 있게 해줍니다. Functools 라이브러리는 기존 함수를 이용하는 함수를 모아놓은 모듈이라고 하겠습니다. Functools 라이브러리에는 partial(), total_ordering(), reduce(), chched_perperty() 등 여러 함수가 있는데요, 이번 포스팅에서는 partial() 메소드에 대해서 소개하겠습니다. 

(* functools.reduce() 함수 참고 : https://rfriend.tistory.com/366)





Functools partial 함수는 기존 파이썬 함수를 재사용하여 일부 위치 매개변수 또는 키워드 매개변수를 고정한(freezed, fixec) 상태에서, 원래의 함수처럼 작동하는 새로운 부분 객체(partial object)를 반환합니다. functools.partial() 함수의 syntax는 아래와 같이, 기존 함수이름을 써주고, 고정할 매개변수 값을 써주면 됩니다.  


from functools import partial


functools.partial(func, /, *args, **keywords)


간단한 예제로서, 숫자나 문자열을 정수(integer)로 변환해주는 파이썬 내장 함수 int(x, base=10)를 재활용하여, base=2 로 고정한 새로운 함수를 functools.partial() 함수로 만들어보겠습니다. 



# python build-in function int(x, base=10)

int('101', base=2)

[Out]: 5

int('101', base=5)

[Out]: 26

 



# create a basetwo() function using functools.partial() and int() function

from functools import partial


basetwo = partial(int, base=2)  # freeze base=2

basetwo('101')

[Out]: 5




int() 함수를 재활용해서 base=2 로 고정해서 새로 만든 basetwo() 라는 이름의 함수에 basetwo.__doc__ 로 설명을 추가하고, 호출해서 확인해보겠습니다. 



# add __doc__ attribute

basetwo.__doc__ = 'Convert base 2 string to an int.'


basetwo.__doc__

[Out]: 'Convert base 2 string to an int.'




functools.partial() 로 만든 새로운 객체는 func, args, keywords 속성(attributes)을 가지고 있습니다. 

이번 예에서는 재활용한 기존 함수(func)가 int(), 키워드 매개변수(keywords)가 base=2 ({'base': 2} 였는데요, 아래처럼 확인할 수 있습니다. 



basetwo.func

[Out]: int


basetwo.args

[Out]: ()


basetwo.keywords

[Out]: {'base': 2}

 



* functools library refreence: https://docs.python.org/3/library/functools.html#module-functools


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

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



728x90
반응형
Posted by Rfriend
,

파이썬 객체를 일정한 규칙(규약)을 따라서 (a) 효율적으로 저장하거나 스트림으로 전송할 때 파이썬 객체의 데이터를 줄로 세워 저장하는 것을 직렬화(serialization) 라고 하고, (b) 이렇게 직렬화된 파일이나 바이트를 원래의 객체로 복원하는 것을 역직렬화(de-serialization)라고 합니다. 


직렬화, 역직렬화를 하는데 Pickle, JSON, YAML 등 여러가지 방법이 있습니다. Pickle 방식은 사람이 읽을 수 없는 반면 저장이나 전송이 효율적입니다. 대신 JSON, YAML 방식은 저장이나 전송이 Pickle 보다는 덜 효율적이지만 사람이 읽을 수 있는 가독성이 좋은 장점이 있습니다. (* 파이썬에서 JSON 데이터 읽고 쓰기: https://rfriend.tistory.com/474)


이번 포스팅에서는 Pickle 방식으로 이진 파일이나 바이트 객체로 직렬화하고, 이를 다시 역직렬화해서 불러오는 방법에 대해서 소개하겠습니다. Pickle 방식에서는 직렬화(serialization)는 Pickling 이라고도 하며, 역직렬화(deserialization)는 Unpickling 이라고도 합니다. 


파이썬에서 Pickle 방식으로 직렬화, 역직렬화하는데는 파이썬으로 작성되고 파이썬 표준 라이브러리에 포함되어 있는 pickle module, C로 작성되어 매우 빠르지만 Subclass 는 지원하지 않는 cPickle module 의 두 가지 패키지를 사용할 수 있습니다. (* source : https://pymotw.com/2/pickle/)


파이썬의 Pickle 방식으로 직렬화할 수 있는 객체는 모든 파이썬 객체를 망라합니다. (정수, 실수, 복소소, 문자열, 블리언, 바이트 객체, 바이트 배열, None, 리스트, 튜플, 사전, 집합, 함수, 클래스, 인스턴스 등)


이번 포스팅에서는 Python 3.7 버전(protocol = 3)에서 pickle 모듈을 사용하여 


(1-1) 파이썬 객체를 직렬화하여 이진 파일(binary file)에 저장하기 : pickle.dump()

(1-2) 직렬화되어 있는 이진 파일로 부터 파이썬 객체로 역직렬화하기: pickle.load()


(2-1) 파이썬 객체를 직렬화하여 메모리에 저장하기: pickle.dumps()

(2-2) 직렬화되어 있는 바이트 객체(bytes object)를 파이썬 객체로 역직렬화: pickle.loads()


로 나누어서 각 방법을 소개하겠습니다. 


pickle.dump()와 pickle.dumps() 메소드, 그리고 pickle.load()와 pickle.loads() 메소드의 끝에 's'가 안붙고 붙고의 차이를 유심히 봐주세요. 


 구분

 Binary File on disk

Bytes object on memory 

 직렬화

(serialization)

 with open("file.txt", "wb") as MyFile:

     pickle.dump(MyObject, MyFile)

 pickle.dumps(MyObject, MyBytes)

 역직렬화

(deserialization)

 with open("file.txt", "rb") as MyFile:

     MyObj2 = pickle.load(MyFile)

 MyObj2 = pickle.loads(MyBytes)




직렬화, 역직렬화를 할 때 일정한 규칙을 따라야 하는데요, 파이썬 버전별로 Pickle Protocol Version 은 아래에 정리한 표를 참고하시기 바랍니다. 그리고 상위 버전의 Pickle Protocol Version에서 저장한 경우 하위 버전에서 역직렬화할 수 없으므로 주의가 필요합니다. (가령 Python 3.x에서 Protocol = 3 으로 직렬화해서 저장한 파일을 Python 2.x 에서 Protocol = 2 버전으로는 역직렬화 할 수 없습니다.)




먼저, 예제로 사용할 정수, 텍스트, 실수, 블리언 고유 자료형을 포함하는 파이썬 사전 객체 (python dictionary object)를 만들어보겠습니다. 



MyObject = {'id': [1, 2, 3, 4], 

           'name': ['KIM', 'CHOI', 'LEE', 'PARK'], 

           'score': [90.5, 85.7, 98.9, 62.4], 

           'pass_yn': [True, True, True, False]}





 (1-1) 파이썬 객체를 직렬화하여 이진 파일(binary file)에 저장하기 : pickle.dump()



import pickle


with open("serialized_file.txt", "wb") as MyFile:

    pickle.dump(MyObject, MyFile, protocol=3)



with open("serialized_file.txt", "wb") as MyFile 함수를 사용해서 "serialized_file.txt" 라는 이름의 파일을 이진 파일 쓰기 모드 ("wb") 로 열어 놓습니다. (참고로, with open() 은 close() 를 해줄 필요가 없습니다.)


pickle.dump(MyObject, MyFile) 로 위에서 만든 MyObject 사전 객체를 MyFile ("serialized_file.txt") 에 직렬화해서 저장합니다. 


Python 3.7 버전에서 작업하고 있으므로 protocol=3 으로 지정해줬는데요, Python 3.0~3.7 버전에서는 기본값이 protocol=3 이므로 안써줘도 괜찮습니다. 


현재의 작업 폴더에 가보면 "serialized_file.txt" 파일이 생성이 되어있을 텐데요, 이 파일을 클릭해서 열어보면 아래와 같이 사람이 읽을 수 없는 binary 형태로 저장이 되어 있습니다. (만약 사람이 읽을 수 있고 가독성이 좋은 저장, 전송을 원한다면 JSON, YAML 등을 사용해서 직렬화 하면됨)





 (1-2) 직렬화되어 있는 이진 파일로 부터 파이썬 객체로 역직렬화: pickle.load()



import pickle


with open("serialized_file.txt", "rb") as MyFile:

    UnpickledObject = pickle.load(MyFile)



UnpickledObject

[Out]:
{'id': [1, 2, 3, 4],
 'name': ['KIM', 'CHOI', 'LEE', 'PARK'],
 'score': [90.5, 85.7, 98.9, 62.4],
 'pass_yn': [True, True, True, False]}


with open("serialized_file.txt", "rb") as MyFile 를 사용하여 위의 (1-1)에서 파이썬 사전 객체를 직렬화하여 이진 파일로 저장했던 "serialized_file.txt" 파일을 이진 파일 읽기 모드 ("rb") 로 MyFile 이름으로 열어 놓습니다. 


UnpickledObject = pickle.load(MyFile) 로 앞에서 열어놓은 MyFile 직렬화된 파일을 역직렬화(de-serialization, unpickling, decoding) 하여 UnpickledObject 라는 이름의 파이썬 객체를 생성합니다. 


이렇게 만든 UnpickledObject 파이썬 객체를 호출해보니 다시 사람이 읽을 수 있는 사전 객체로 다시 잘 복원되었음을 알 수 있습니다. 




 (2-1) 파이썬 객체를 직렬화하여 메모리에 Bytes object로 저장하기pickle.dumps()



import pickle 


MyBytes = pickle.dumps(MyObject, protocol=3)



# unreadable bytes object

MyBytes

[Out]:

b'\x80\x03}q\x00(X\x02\x00\x00\x00idq\x01]q\x02(K\x01K\x02K\x03K\x04eX\x04\x00\x00\x00nameq\x03]q\x04(X\x03\x00\x00\x00KIMq\x05X\x04\x00\x00\x00CHOIq\x06X\x03\x00\x00\x00LEEq\x07X\x04\x00\x00\x00PARKq\x08eX\x05\x00\x00\x00scoreq\t]q\n(G@V\xa0\x00\x00\x00\x00\x00G@Ul\xcc\xcc\xcc\xcc\xcdG@X\xb9\x99\x99\x99\x99\x9aG@O333333eX\x07\x00\x00\x00pass_ynq\x0b]q\x0c(\x88\x88\x88\x89eu.'



위의 (1-1)이 파이썬 객체를 이진 파일(binary file) 로 로컬 디스크에 저장하였다면, 이번 (2-1)은 pickle.dumps(object_name, protocol=3) 을 사용해서 메모리에 Bytes object로 직렬화해서 저장하는 방법입니다. pickle.dumps() 메소드의 제일 뒤에 's'가 추가로 붙어있는 것 유의하세요. 


이렇게 직렬화해서 저장한 Bytes object의 경우 사람이 읽을 수 없는 형태입니다. (반면, 컴퓨터한테는 데이터를 저장하기에 더 효율적인 형태)




 (2-2) 직렬화되어 있는 바이트 객체를 파이썬 객체로 역직렬화: pickle.loads()



import pickle


MyObj2 = pickle.loads(MyBytes)


MyObj2

[Out]:
{'id': [1, 2, 3, 4],
 'name': ['KIM', 'CHOI', 'LEE', 'PARK'],
 'score': [90.5, 85.7, 98.9, 62.4],
 'pass_yn': [True, True, True, False]}

 


위의 (2-1)에서 직렬화하여 저장한 바이트 객체 MyBytes 를 pickle.loads() 메소드를 사용하여 역직렬화하여 MyObj2 라는 이름의 파이썬 객체를 생성한 예입니다.  


* reference: https://docs.python.org/3.7/library/pickle.html

* pickle and cPicklehttps://pymotw.com/2/pickle/


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

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



728x90
반응형
Posted by Rfriend
,